├── .gitignore
├── .travis.yml
├── 4-application-full-stack.yaml
├── DigiCertAssuredIDCAG2.crt.pem
├── Dockerfile
├── README.md
├── ReadMes
└── IstioClass.md
├── account-service.json.enc
├── ca.crt
├── deploy.sh
├── docker-compose.yml
├── index.html
├── k8s
├── 4-application-full-stack.yaml
├── clusterRole.yaml
├── tikitaka-app.yaml
└── tikitaka-istio.yaml
├── k8sTests
├── api-access-role-bindling.yaml
└── tikitaka-auth.yaml
├── package-lock.json
├── package.json
├── server
├── config
│ └── keys.js
├── controllers
│ ├── abTestController.js
│ ├── createDepController.js
│ ├── historyController.js
│ ├── testController.js
│ └── testControllerIstio.js
├── models
│ ├── abTestModel.js
│ └── historyModels.js
└── server.js
├── skaffold.yaml
├── src
├── assets
│ ├── IMG_9802.png
│ ├── deployment.json
│ ├── destinationrules.json
│ ├── gateway.json
│ ├── github-resume.jpg
│ ├── img1.png
│ ├── mario.png
│ ├── service.json
│ └── virtualservice.json
├── components
│ ├── About.tsx
│ ├── App.tsx
│ ├── Bullets.tsx
│ ├── FetcherComponent.tsx
│ ├── Sidebar.tsx
│ ├── TestDisplay.tsx
│ └── TestForm.tsx
├── context
│ ├── historyContext.tsx
│ └── tikitakaContext.tsx
├── index.tsx
└── styles
│ └── app.scss
├── token
├── tsconfig.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 |
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .idea
15 | .idea/workspace.xml
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | sudo: required
3 | services:
4 | - docker
5 | env:
6 | global:
7 | - "SHA=$(git rev-parse HEAD)"
8 | - "CLOUDSDK_CORE_DISABLE_PROMPTS=1"
9 | before_install:
10 | - "openssl aes-256-cbc -K $encrypted_6e1b6df37de9_key -iv $encrypted_6e1b6df37de9_iv -in account-service.json.enc -out account-service.json -d"
11 | - "curl https://sdk.cloud.google.com | bash > /dev/null;"
12 | - "source ~/google-cloud-sdk/path.zsh.inc"
13 | - "gcloud components update kubectl"
14 | - "gcloud auth activate-service-account --key-file account-service.json"
15 | - "gcloud config set project tikitakastage"
16 | - "gcloud config set compute/region us-west2"
17 | - "gcloud container clusters get-credentials tikitakastage --region=us-west2"
18 | - "echo \"$DOCKER_PASSWORD\" | docker login -u \"$DOCKER_USERNAME\" --password-stdin"
19 | - "docker build -t tikitaka1/general -f ./Dockerfile ./"
20 | deploy:
21 | provider: script
22 | script: "bash ./deploy.sh"
23 | on:
24 | branch: master
25 |
--------------------------------------------------------------------------------
/4-application-full-stack.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: position-simulator
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: position-simulator
9 | replicas: 1
10 | template: # template for the pods
11 | metadata:
12 | labels:
13 | app: position-simulator
14 | spec:
15 | containers:
16 | - name: position-simulator
17 | image: richardchesterwood/istio-fleetman-position-simulator:5
18 | env:
19 | - name: SPRING_PROFILES_ACTIVE
20 | value: production-microservice
21 | command: ["java","-Xmx50m","-jar","webapp.jar"]
22 | imagePullPolicy: Always
23 | ---
24 | apiVersion: apps/v1
25 | kind: Deployment
26 | metadata:
27 | name: position-tracker
28 | spec:
29 | selector:
30 | matchLabels:
31 | app: position-tracker
32 | replicas: 1
33 | template: # template for the pods
34 | metadata:
35 | labels:
36 | app: position-tracker
37 | spec:
38 | containers:
39 | - name: position-tracker
40 | image: richardchesterwood/istio-fleetman-position-tracker:5
41 | env:
42 | - name: SPRING_PROFILES_ACTIVE
43 | value: production-microservice
44 | command: ["java","-Xmx50m","-jar","webapp.jar"]
45 | imagePullPolicy: Always
46 | ---
47 | apiVersion: apps/v1
48 | kind: Deployment
49 | metadata:
50 | name: api-gateway
51 | spec:
52 | selector:
53 | matchLabels:
54 | app: api-gateway
55 | replicas: 1
56 | template: # template for the pods
57 | metadata:
58 | labels:
59 | app: api-gateway
60 | version: v2
61 | spec:
62 | containers:
63 | - name: api-gateway
64 | image: richardchesterwood/istio-fleetman-api-gateway:5
65 | env:
66 | - name: SPRING_PROFILES_ACTIVE
67 | value: production-microservice
68 | command: ["java","-Xmx50m","-jar","webapp.jar"]
69 | imagePullPolicy: Always
70 | ---
71 | apiVersion: apps/v1
72 | kind: Deployment
73 | metadata:
74 | name: webapp
75 | spec:
76 | selector:
77 | matchLabels:
78 | app: webapp
79 | replicas: 1
80 | template: # template for the pods
81 | metadata:
82 | labels:
83 | app: webapp
84 | spec:
85 | containers:
86 | - name: webapp
87 | image: richardchesterwood/istio-fleetman-webapp-angular:5
88 | env:
89 | - name: SPRING_PROFILES_ACTIVE
90 | value: production-microservice
91 | imagePullPolicy: Always
92 | ---
93 | apiVersion: apps/v1
94 | kind: Deployment
95 | metadata:
96 | name: vehicle-telemetry
97 | spec:
98 | selector:
99 | matchLabels:
100 | app: vehicle-telemetry
101 | replicas: 1
102 | template: # template for the pods
103 | metadata:
104 | labels:
105 | app: vehicle-telemetry
106 | spec:
107 | containers:
108 | - name: vehicle-telemtry
109 | image: richardchesterwood/istio-fleetman-vehicle-telemetry:5
110 | env:
111 | - name: SPRING_PROFILES_ACTIVE
112 | value: production-microservice
113 | imagePullPolicy: Always
114 | ---
115 | apiVersion: apps/v1
116 | kind: Deployment
117 | metadata:
118 | name: staff-service
119 | spec:
120 | selector:
121 | matchLabels:
122 | app: staff-service
123 | replicas: 1
124 | template: # template for the pods
125 | metadata:
126 | labels:
127 | app: staff-service
128 | spec:
129 | containers:
130 | - name: staff-service
131 | image: richardchesterwood/istio-fleetman-staff-service:5
132 | env:
133 | - name: SPRING_PROFILES_ACTIVE
134 | value: production-microservice
135 | imagePullPolicy: Always
136 | ---
137 | apiVersion: apps/v1
138 | kind: Deployment
139 | metadata:
140 | name: photo-service
141 | spec:
142 | selector:
143 | matchLabels:
144 | app: photo-service
145 | replicas: 1
146 | template: # template for the pods
147 | metadata:
148 | labels:
149 | app: photo-service
150 | spec:
151 | containers:
152 | - name: photo-service
153 | image: richardchesterwood/istio-fleetman-photo-service:5
154 | env:
155 | - name: SPRING_PROFILES_ACTIVE
156 | value: production-microservice
157 | imagePullPolicy: Always
158 | ---
159 | apiVersion: v1
160 | kind: Service
161 | metadata:
162 | name: fleetman-webapp
163 | spec:
164 | # This defines which pods are going to be represented by this Service
165 | # The service becomes a network endpoint for either other services
166 | # or maybe external users to connect to (eg browser)
167 | selector:
168 | app: webapp
169 | ports:
170 | - name: http
171 | port: 80
172 | nodePort: 30080
173 | type: NodePort
174 | ---
175 | apiVersion: v1
176 | kind: Service
177 | metadata:
178 | name: fleetman-position-tracker
179 |
180 | spec:
181 | # This defines which pods are going to be represented by this Service
182 | # The service becomes a network endpoint for either other services
183 | # or maybe external users to connect to (eg browser)
184 | selector:
185 | app: position-tracker
186 | ports:
187 | - name: http
188 | port: 8080
189 | type: ClusterIP
190 | ---
191 | apiVersion: v1
192 | kind: Service
193 | metadata:
194 | name: fleetman-api-gateway
195 | spec:
196 | selector:
197 | app: api-gateway
198 | ports:
199 | - name: http
200 | port: 8080
201 | type: ClusterIP
202 | ---
203 | apiVersion: v1
204 | kind: Service
205 | metadata:
206 | name: fleetman-vehicle-telemetry
207 | spec:
208 | selector:
209 | app: vehicle-telemetry
210 | ports:
211 | - name: http
212 | port: 8080
213 | type: ClusterIP
214 | ---
215 | apiVersion: v1
216 | kind: Service
217 | metadata:
218 | name: fleetman-staff-service
219 | spec:
220 | selector:
221 | app: staff-service
222 | ports:
223 | - name: http
224 | port: 8080
225 | type: ClusterIP
226 | ---
227 | apiVersion: v1
228 | kind: Service
229 | metadata:
230 | name: fleetman-photo-service
231 | spec:
232 | selector:
233 | app: photo-service
234 | ports:
235 | - name: http
236 | port: 8080
237 | type: ClusterIP
238 | ---
239 | # See case #23
240 | apiVersion: networking.istio.io/v1alpha3
241 | kind: ServiceEntry
242 | metadata:
243 | name: fleetman-driver-monitoring
244 | spec:
245 | hosts:
246 | - 2oujlno5e4.execute-api.us-east-1.amazonaws.com
247 | location: MESH_EXTERNAL
248 | ports:
249 | - number: 80
250 | name: http-port
251 | protocol: HTTP
252 | - number: 443
253 | name: https-port-for-tls-origination
254 | protocol: HTTPS
255 | resolution: DNS
256 | ---
257 | # See case #23 - this is a legacy service that we're integrating with
258 | apiVersion: networking.istio.io/v1alpha3
259 | kind: VirtualService
260 | metadata:
261 | name: fleetman-driver-monitoring
262 | spec:
263 | hosts:
264 | - 2oujlno5e4.execute-api.us-east-1.amazonaws.com
265 | http:
266 | - match:
267 | - port: 80
268 | route:
269 | - destination:
270 | host: 2oujlno5e4.execute-api.us-east-1.amazonaws.com
271 | port:
272 | number: 443
273 | ---
274 | apiVersion: networking.istio.io/v1alpha3
275 | kind: DestinationRule
276 | metadata:
277 | name: fleetman-driver-monitoring
278 | spec:
279 | host: 2oujlno5e4.execute-api.us-east-1.amazonaws.com
280 | trafficPolicy:
281 | loadBalancer:
282 | simple: ROUND_ROBIN
283 | portLevelSettings:
284 | - port:
285 | number: 443
286 | tls:
287 | mode: SIMPLE
288 |
--------------------------------------------------------------------------------
/DigiCertAssuredIDCAG2.crt.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEmjCCA4KgAwIBAgIQD1/M/Ksg89+ObaPYR2fCkzANBgkqhkiG9w0BAQsFADBl
3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4 | d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
5 | b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMjgwODAxMTIwMDAwWjBIMQswCQYDVQQG
6 | EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSIwIAYDVQQDExlEaWdpQ2VydCBB
7 | c3N1cmVkIElEIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
8 | tFLF3hmmiyDchhlz2ZMtsf4L23l6z+g5odzcrNDI8QcZTBUm9xV9w5YZ6bRXU7jw
9 | ZlKaaVtxrqugWHNdlNfKL27RzC4kn1aKvwdt5Gj9j+UMzc/BMx3ksvGiHwQMBMGF
10 | zPAVG9aUpVXCXdUt0vSOLZxzI3x2Oqz2jL9pxc2l/bmgf9uhE4v2noPxViUQ4DF2
11 | h/cDRzV5qyZUq8FPw9y1JUi8Pl6HHAzFei/4OvhAQogerd8lvl8chlkT5h9UNeS0
12 | zdv5uDrNs5C/hJqXidKZU7nZTqh08B/RD8vsu9f66HavmbyrKXa2CveC0uqZvfQZ
13 | 0SBCj4ykeElnxyveHfOvUQIDAQABo4IBYTCCAV0wEgYDVR0TAQH/BAgwBgEB/wIB
14 | ADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho
15 | dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6
16 | Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmww
17 | OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
18 | RFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
19 | dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFLHP9qHl5oHFZkeN
20 | eIR3e/mBy0qmMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA0GCSqG
21 | SIb3DQEBCwUAA4IBAQA/C7UkzAlgi5mvLq7ukp0JS9Vg+rMNyx3XVkBF84vz9exk
22 | 74Y0vPnniZoy/pAgOaFFGbsVBI7SNf/iGI5x5UG5PKWo+K0AP0fwkZFnfEAN0wJy
23 | Dezr2oLi95s2XCoqThxhtJe6t1A8Lh6klGQGkgREdyF7Y6obGQq+7hDz4VRR4MCM
24 | m5QHcPcYJzh0pQueTxadgp6AbksehUf/g9eGzwzHqdkkAIQ9mzpRRxjoqkaPTtSd
25 | kpPl/ZZcDqPzDzWXhzKfJs90lSuYy1z1fQEgFZP/X1DGT8SGzAlfv83e+FC3ja7w
26 | JZJ4ZTqw8UTUUpI52U2HVCMXKNtEFEyMYLeRJe+j
27 | -----END CERTIFICATE-----
28 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:13
2 | WORKDIR /usr/src/app
3 | COPY ./package.json .
4 | RUN npm install
5 | COPY ./ ./
6 | RUN npm run build
7 | EXPOSE 3000
8 | # CMD ["node", "./server/server.js"]
9 | CMD ["npm", "start"]
10 |
11 |
12 | # FROM node:13
13 |
14 | # WORKDIR /usr/src/app
15 |
16 | # COPY . .
17 |
18 | # RUN npm install
19 |
20 | # RUN npm run build
21 |
22 | # EXPOSE 3000
23 |
24 | # CMD ["node", "./server/server.js"]
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Istio-AB-testing
--------------------------------------------------------------------------------
/ReadMes/IstioClass.md:
--------------------------------------------------------------------------------
1 | #### Istio
2 |
3 | ##### Sticky Sessions
4 |
5 | ##### What is Consistent Hashing Useful For
6 | - Feign equivalent for Node.js to be found, for header propagation.
7 | - Using headers for consistent hashing may not be very good because each heather needs to be propagated.
8 | - [] Envoy proxy issue 8167.
9 | - General Consistent Hashing useful for: equally distributing balancing traffic.
10 | - Sticky solution does not create a session, because pod that is hashed might fail.
11 |
12 | ##### Gateways
13 | ###### Ingress Gateways
14 | - Kuberetes Ingress Resource and Istio Gateway are different
15 | - In match conditions for a Virtual Service, the same level contions represents OR conditions.
16 | ```
17 | kind: Virutal Service
18 | ........
19 | http:
20 | - match:
21 | - uri: #IF
22 | prefix: "/experimental"
23 | - uri: #OR
24 | prefix: "/canary"
25 | route: #THEN
26 | - destination:
27 | host: fleetman-webapp
28 | subset: experimental
29 | weight: 100
30 | - match:
31 | - uri:
32 | prefix: "/"
33 | route:
34 | - destination:
35 | host: fleetman-webapp
36 | subset: original
37 | ```
38 | #### Dark Releases
39 | > Definition: We can deploy another version of the app and give it a different header when making requests to the back
40 | > end, that header usually is only known by the developers, so it can be tested within the live server.
41 | ###### Header Routing Example:
42 | ```
43 | kind: Virtual Service
44 | ...........
45 | http:
46 | - name: "rule 1"
47 | match:
48 | - headers:
49 | my-header:
50 | exact: canary
51 | route:
52 | - destination:
53 | host: fleetman-webapp
54 | subset: experimental
55 | - name: "rule 2" #CATCH ALL
56 | route:
57 | - destination:
58 | host: fleetman-webapp
59 | subset: original
60 | ```
61 | - If you do not write a matching condition to the rule, it becomes a catch all route.
62 |
--------------------------------------------------------------------------------
/account-service.json.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Tikitaka/2e97fbb94890e95a831a101d88628cb1d95d1d6c/account-service.json.enc
--------------------------------------------------------------------------------
/ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
3 | cm5ldGVzMB4XDTIwMDEyNDA2MjgyOFoXDTMwMDEyMTA2MjgyOFowFTETMBEGA1UE
4 | AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhj
5 | YAlh/Z6qjem0w+XdsEK5QKlax2C+mhbtffpsV2LWrshOPAIT4T78AMhIhGlbT2Ad
6 | UDZdR9dTM7jjOyc+S8vP0PV4OlG5VGWOvidnaK5/JTmSJBkMOvydQqx1cU4IzAnb
7 | GUts0N6rtpY95T9elWvOzr2C5CJgda3/iojW9FiDt3ovZdGrbJbrAXh/TNt0k/s8
8 | SEhQlR9PFm6bfgZWmJHFj8c1BtxQ3vNd38jiIUvR/kMm74xkDPUzAW2Rw8zSrhqK
9 | KdxiaH8BYY5lq/5iuhOE6FaRmNnADSO40H6U3sEjRXXuKD/PpWwVWfynvmQVufub
10 | g1/VHNVqHc3Hrl4aJhECAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
11 | /wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABIi7HvxaS0mnk+BHkiYQ8sSVu52
12 | 4ekDRw8NpaJbrSfip5kroLU+am/stODPjBXE3ALvyrMLiXseGLJDYR1cMZY1JvvA
13 | Y9/JUHpusc4Wd3g+s10P6P7sIgUh9RJ3Y83NWh76xAA98lUf/uFQOzAO/DPQT97y
14 | dlwOO2ydFNNNVwNhLQdYC1cZHT03NuWCGHXr8xVz1toEeUSYRmsBPRhgj7JZ9VzN
15 | HjOjxdbv/y+SnhcXgyxaaIUKLK+n/a62y//X9EzVeAr0HQsD7MpFzt/SAwXA/03U
16 | szYyd3UnItjzrHVXVONpODv149Z8wfnytRbgv02N7sHGhLJ38Jh0r+Hd3zk=
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | docker build -t tikitaka1/general:latest -t tikitaka1/general:$SHA -f ./Dockerfile ./
2 | docker push tikitaka1/general:latest
3 | docker push armangurkan1/multi-client:$SHA
4 | kubectl apply -f ./k8s
5 | kubectl set image deployments/general-deployment general=tikitaka1/general:$SHA
6 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | tikitaka:
5 | restart: always
6 | build:
7 | dockerfile: Dockerfile
8 | context: ./
9 | ports:
10 | - "3000:3000"
11 | volumes:
12 | - /usr/src/app/node_modules
13 | - ./:/usr/src/app
14 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | TIKITAKA
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/k8s/4-application-full-stack.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: position-simulator
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: position-simulator
9 | replicas: 1
10 | template: # template for the pods
11 | metadata:
12 | labels:
13 | app: position-simulator
14 | spec:
15 | containers:
16 | - name: position-simulator
17 | image: richardchesterwood/istio-fleetman-position-simulator:5
18 | env:
19 | - name: SPRING_PROFILES_ACTIVE
20 | value: production-microservice
21 | command: ["java","-Xmx50m","-jar","webapp.jar"]
22 | imagePullPolicy: Always
23 | ---
24 | apiVersion: apps/v1
25 | kind: Deployment
26 | metadata:
27 | name: position-tracker
28 | spec:
29 | selector:
30 | matchLabels:
31 | app: position-tracker
32 | replicas: 1
33 | template: # template for the pods
34 | metadata:
35 | labels:
36 | app: position-tracker
37 | spec:
38 | containers:
39 | - name: position-tracker
40 | image: richardchesterwood/istio-fleetman-position-tracker:5
41 | env:
42 | - name: SPRING_PROFILES_ACTIVE
43 | value: production-microservice
44 | command: ["java","-Xmx50m","-jar","webapp.jar"]
45 | imagePullPolicy: Always
46 | ---
47 | apiVersion: apps/v1
48 | kind: Deployment
49 | metadata:
50 | name: api-gateway
51 | spec:
52 | selector:
53 | matchLabels:
54 | app: api-gateway
55 | replicas: 1
56 | template: # template for the pods
57 | metadata:
58 | labels:
59 | app: api-gateway
60 | version: v2
61 | spec:
62 | containers:
63 | - name: api-gateway
64 | image: richardchesterwood/istio-fleetman-api-gateway:5
65 | env:
66 | - name: SPRING_PROFILES_ACTIVE
67 | value: production-microservice
68 | command: ["java","-Xmx50m","-jar","webapp.jar"]
69 | imagePullPolicy: Always
70 | ---
71 | apiVersion: apps/v1
72 | kind: Deployment
73 | metadata:
74 | name: webapp
75 | spec:
76 | selector:
77 | matchLabels:
78 | app: webapp
79 | replicas: 1
80 | template: # template for the pods
81 | metadata:
82 | labels:
83 | app: webapp
84 | spec:
85 | containers:
86 | - name: webapp
87 | image: richardchesterwood/istio-fleetman-webapp-angular:5
88 | env:
89 | - name: SPRING_PROFILES_ACTIVE
90 | value: production-microservice
91 | imagePullPolicy: Always
92 | ---
93 | apiVersion: apps/v1
94 | kind: Deployment
95 | metadata:
96 | name: vehicle-telemetry
97 | spec:
98 | selector:
99 | matchLabels:
100 | app: vehicle-telemetry
101 | replicas: 1
102 | template: # template for the pods
103 | metadata:
104 | labels:
105 | app: vehicle-telemetry
106 | spec:
107 | containers:
108 | - name: vehicle-telemtry
109 | image: richardchesterwood/istio-fleetman-vehicle-telemetry:5
110 | env:
111 | - name: SPRING_PROFILES_ACTIVE
112 | value: production-microservice
113 | imagePullPolicy: Always
114 | ---
115 | apiVersion: apps/v1
116 | kind: Deployment
117 | metadata:
118 | name: staff-service
119 | spec:
120 | selector:
121 | matchLabels:
122 | app: staff-service
123 | replicas: 1
124 | template: # template for the pods
125 | metadata:
126 | labels:
127 | app: staff-service
128 | spec:
129 | containers:
130 | - name: staff-service
131 | image: richardchesterwood/istio-fleetman-staff-service:5
132 | env:
133 | - name: SPRING_PROFILES_ACTIVE
134 | value: production-microservice
135 | imagePullPolicy: Always
136 | ---
137 | apiVersion: apps/v1
138 | kind: Deployment
139 | metadata:
140 | name: photo-service
141 | spec:
142 | selector:
143 | matchLabels:
144 | app: photo-service
145 | replicas: 1
146 | template: # template for the pods
147 | metadata:
148 | labels:
149 | app: photo-service
150 | spec:
151 | containers:
152 | - name: photo-service
153 | image: richardchesterwood/istio-fleetman-photo-service:5
154 | env:
155 | - name: SPRING_PROFILES_ACTIVE
156 | value: production-microservice
157 | imagePullPolicy: Always
158 | ---
159 | apiVersion: v1
160 | kind: Service
161 | metadata:
162 | name: fleetman-webapp
163 | spec:
164 | # This defines which pods are going to be represented by this Service
165 | # The service becomes a network endpoint for either other services
166 | # or maybe external users to connect to (eg browser)
167 | selector:
168 | app: webapp
169 | ports:
170 | - name: http
171 | port: 80
172 | nodePort: 30080
173 | type: NodePort
174 | ---
175 | apiVersion: v1
176 | kind: Service
177 | metadata:
178 | name: fleetman-position-tracker
179 |
180 | spec:
181 | # This defines which pods are going to be represented by this Service
182 | # The service becomes a network endpoint for either other services
183 | # or maybe external users to connect to (eg browser)
184 | selector:
185 | app: position-tracker
186 | ports:
187 | - name: http
188 | port: 8080
189 | type: ClusterIP
190 | ---
191 | apiVersion: v1
192 | kind: Service
193 | metadata:
194 | name: fleetman-api-gateway
195 | spec:
196 | selector:
197 | app: api-gateway
198 | ports:
199 | - name: http
200 | port: 8080
201 | type: ClusterIP
202 | ---
203 | apiVersion: v1
204 | kind: Service
205 | metadata:
206 | name: fleetman-vehicle-telemetry
207 | spec:
208 | selector:
209 | app: vehicle-telemetry
210 | ports:
211 | - name: http
212 | port: 8080
213 | type: ClusterIP
214 | ---
215 | apiVersion: v1
216 | kind: Service
217 | metadata:
218 | name: fleetman-staff-service
219 | spec:
220 | selector:
221 | app: staff-service
222 | ports:
223 | - name: http
224 | port: 8080
225 | type: ClusterIP
226 | ---
227 | apiVersion: v1
228 | kind: Service
229 | metadata:
230 | name: fleetman-photo-service
231 | spec:
232 | selector:
233 | app: photo-service
234 | ports:
235 | - name: http
236 | port: 8080
237 | type: ClusterIP
238 | ---
239 | # See case #23
240 | apiVersion: networking.istio.io/v1alpha3
241 | kind: ServiceEntry
242 | metadata:
243 | name: fleetman-driver-monitoring
244 | spec:
245 | hosts:
246 | - 2oujlno5e4.execute-api.us-east-1.amazonaws.com
247 | location: MESH_EXTERNAL
248 | ports:
249 | - number: 80
250 | name: http-port
251 | protocol: HTTP
252 | - number: 443
253 | name: https-port-for-tls-origination
254 | protocol: HTTPS
255 | resolution: DNS
256 | ---
257 | # See case #23 - this is a legacy service that we're integrating with
258 | apiVersion: networking.istio.io/v1alpha3
259 | kind: VirtualService
260 | metadata:
261 | name: fleetman-driver-monitoring
262 | spec:
263 | hosts:
264 | - 2oujlno5e4.execute-api.us-east-1.amazonaws.com
265 | http:
266 | - match:
267 | - port: 80
268 | route:
269 | - destination:
270 | host: 2oujlno5e4.execute-api.us-east-1.amazonaws.com
271 | port:
272 | number: 443
273 | ---
274 | apiVersion: networking.istio.io/v1alpha3
275 | kind: DestinationRule
276 | metadata:
277 | name: fleetman-driver-monitoring
278 | spec:
279 | host: 2oujlno5e4.execute-api.us-east-1.amazonaws.com
280 | trafficPolicy:
281 | loadBalancer:
282 | simple: ROUND_ROBIN
283 | portLevelSettings:
284 | - port:
285 | number: 443
286 | tls:
287 | mode: SIMPLE
288 |
--------------------------------------------------------------------------------
/k8s/clusterRole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1beta1
2 | kind: ClusterRole
3 | metadata:
4 | name: api-access
5 | rules:
6 | -
7 | apiGroups:
8 | - "*"
9 | resources:
10 | - "*"
11 | verbs: ["*"]
12 | - nonResourceURLs: ["*"]
13 | verbs: ["*"]
14 | ---
15 | apiVersion: rbac.authorization.k8s.io/v1beta1
16 | kind: ClusterRoleBinding
17 | metadata:
18 | name: api-access
19 | roleRef:
20 | apiGroup: rbac.authorization.k8s.io
21 | kind: ClusterRole
22 | name: api-access
23 | subjects:
24 | - kind: ServiceAccount
25 | name: api-service-account
26 | namespace: default
--------------------------------------------------------------------------------
/k8s/tikitaka-app.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: tikitaka
5 | labels:
6 | app: tikitaka
7 | spec:
8 | selector:
9 | app: tikitaka
10 | ports:
11 | - name: http
12 | port: 3000
13 | ---
14 | apiVersion: apps/v1
15 | kind: Deployment
16 | metadata:
17 | name: tikitaka
18 | labels:
19 | version: v1
20 | spec:
21 | replicas: 1
22 | selector:
23 | matchLabels:
24 | app: tikitaka
25 | template:
26 | metadata:
27 | labels:
28 | app: tikitaka
29 | version: v1
30 | spec:
31 | serviceAccountName: api-service-account
32 | containers:
33 | - name: tikitaka
34 | image: tikitaka1/tikitaka-stage
35 | ports:
36 | - containerPort: 3000
37 | imagePullPolicy: Always
38 |
--------------------------------------------------------------------------------
/k8s/tikitaka-istio.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: Gateway
3 | metadata:
4 | name: tikitaka-gateway
5 | spec:
6 | selector:
7 | istio: ingressgateway
8 | servers:
9 | - port:
10 | number: 80
11 | name: http
12 | protocol: HTTP
13 | hosts:
14 | - "*"
15 | ---
16 | apiVersion: networking.istio.io/v1alpha3
17 | kind: VirtualService
18 | metadata:
19 | name: tikitaka
20 | spec:
21 | hosts:
22 | - "*"
23 | gateways:
24 | - tikitaka-gateway
25 | http:
26 | - route:
27 | - destination:
28 | host: tikitaka
29 |
--------------------------------------------------------------------------------
/k8sTests/api-access-role-bindling.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1beta1
2 | kind: ClusterRole
3 | metadata:
4 | name: api-access
5 | rules:
6 | -
7 | apiGroups: ["*"]
8 | resources: ["*"]
9 | verbs: ["*"]
10 | - nonResourceURLs: ["*"]
11 | verbs: ["*"]
12 | ---
13 | apiVersion: rbac.authorization.k8s.io/v1beta1
14 | kind: ClusterRoleBinding
15 | metadata:
16 | name: api-access
17 | roleRef:
18 | apiGroup: rbac.authorization.k8s.io
19 | kind: ClusterRole
20 | name: api-access
21 | subjects:
22 | - kind: ServiceAccount
23 | name: api-service-account
24 | namespace: default
25 |
--------------------------------------------------------------------------------
/k8sTests/tikitaka-auth.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: tikitaka
5 | labels:
6 | app: tikitaka
7 | spec:
8 | selector:
9 | app: tikitaka
10 | ports:
11 | - name: http
12 | port: 3000
13 | ---
14 | apiVersion: apps/v1
15 | kind: Deployment
16 | metadata:
17 | name: tikitaka
18 | labels:
19 | version: v1
20 | spec:
21 | replicas: 1
22 | selector:
23 | matchLabels:
24 | app: tikitaka
25 | template:
26 | metadata:
27 | labels:
28 | app: tikitaka
29 | version: v1
30 | spec:
31 | containers:
32 | - name: tikitaka
33 | image: tikitaka1/tikitaka-stage:latest
34 | ports:
35 | - containerPort: 3000
36 | imagePullPolicy: Always
37 | volumeMounts:
38 | - name: tikitaka-certs
39 | mountPath: /certs
40 | # Create on-disk volume to store exec logs
41 | - mountPath: /tmp
42 | name: tmp-volume
43 | volumes:
44 | - name: tikitaka-certs
45 | secret:
46 | secretName: tikitaka-certs
47 | - name: tmp-volume
48 | emptyDir: {}
49 | serviceAccountName: tikitaka
50 | # Comment the following tolerations if Dashboard must not be deployed on master
51 | # tolerations:
52 | # - key: node-role.kubernetes.io/master
53 | # effect: NoSchedule
54 |
55 | ---
56 | apiVersion: v1
57 | kind: ServiceAccount
58 | metadata:
59 | labels:
60 | app: tikitaka
61 | name: tikitaka
62 | namespace: default
63 |
64 | ---
65 | apiVersion: v1
66 | kind: Secret
67 | metadata:
68 | labels:
69 | app: tikitaka
70 | name: tikitaka-certs
71 | namespace: kube-system
72 | type: Opaque
73 |
74 | ---
75 | kind: ClusterRole
76 | apiVersion: rbac.authorization.k8s.io/v1
77 | metadata:
78 | name: tikitaka
79 | namespace: default
80 | rules:
81 | - apiGroups: ["", "apps", "*"]
82 | resources: ["*"]
83 | verbs: ["*"]
84 |
85 | ---
86 |
87 | kind: ClusterRoleBinding
88 | apiVersion: rbac.authorization.k8s.io/v1
89 | metadata:
90 | name: tikitaka-role-binding
91 | namespace: default
92 | subjects:
93 | - kind: ServiceAccount
94 | name: tikitaka
95 | namespace: default
96 | roleRef:
97 | apiGroup: rbac.authorization.k8s.io
98 | kind: ClusterRole
99 | name: tikitaka
100 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dash",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --config ./webpack.config.js",
8 | "start": "node ./server/server.js webpack-dev-server",
9 | "dev": "NODE_ENV=development nodemon ./server/server.js & webpack-dev-server --open --hot --inline --progress --colors --watch --content-base ./",
10 | "docker-dev:hot": "docker-compose -f docker-compose-dev-hot.yml up",
11 | "test": "NODE_ENV=test jest --coverage"
12 | },
13 | "nodemonConfig": {
14 | "ignore": [
15 | "build",
16 | "src"
17 | ]
18 | },
19 | "author": "",
20 | "license": "ISC",
21 | "dependencies": {
22 | "@nivo/bullet": "^0.61.1",
23 | "@types/d3-shape": "^1.3.2",
24 | "@types/react-router-dom": "^5.1.3",
25 | "@vx/gradient": "0.0.193-alpha.2",
26 | "@vx/hierarchy": "0.0.193-alpha.2",
27 | "@vx/network": "0.0.193-alpha.2",
28 | "@vx/shape": "0.0.193-alpha.2",
29 | "bootstrap": "^4.4.1",
30 | "cors": "^2.8.5",
31 | "d3-hierarchy": "^1.1.9",
32 | "d3-shape": "^1.3.7",
33 | "express": "^4.17.1",
34 | "kubernetes-client": "^8.3.6",
35 | "node-fetch": "^2.6.0",
36 | "react": "^16.12.0",
37 | "react-bootstrap": "^1.0.0-beta.16",
38 | "react-dom": "^16.12.0",
39 | "react-router-dom": "^5.1.2",
40 | "request": "^2.88.0",
41 | "skaffold": "^1.0.11",
42 | "xmlhttprequest": "^1.8.0"
43 | },
44 | "devDependencies": {
45 | "nodemon": "^2.0.2",
46 | "@babel/preset-env": "^7.8.3",
47 | "@babel/preset-react": "^7.8.3",
48 | "@types/react": "^16.9.19",
49 | "@types/react-dom": "^16.9.5",
50 | "css-loader": "^3.4.2",
51 | "html-webpack-plugin": "^3.2.0",
52 | "mini-css-extract-plugin": "^0.9.0",
53 | "node-sass": "^4.13.1",
54 | "sass-loader": "^8.0.2",
55 | "source-map-loader": "^0.2.4",
56 | "style-loader": "^1.1.3",
57 | "ts-loader": "^6.2.1",
58 | "typescript": "^3.7.5",
59 | "webpack": "^4.41.5",
60 | "webpack-cli": "^3.3.10",
61 | "webpack-dev-server": "^3.10.1"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/server/config/keys.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | MONGO_URI: "mongodb+srv://tikitaka:tikitaka1234@cluster0-ldp4w.mongodb.net/test?retryWrites=true&w=majority"
3 | }
--------------------------------------------------------------------------------
/server/controllers/abTestController.js:
--------------------------------------------------------------------------------
1 | const ABTest = require('../models/abTestModel');
2 |
3 | const abTestController = {};
4 | abTestController.verifyAB_compatibility = (req, res, next) => {
5 | //req body parameters of for testB field should all be included in testA fields or else return error.
6 | };
7 | abTestController.createABTest = (req, res, next) => {
8 |
9 | };
10 | abTestController.startABTest = (req, res, next) => {}
11 | abTestController.updateABTest = (req, res, next) => {}
12 | abTestController.getABTest = (req, res, next) => {}
13 | abTestController.getAllABTests = (req, res, next) => {}
14 | abTestController.stopABTest = (req, res, next) => {}
15 | abTestController.archiveABTest = (req, res, next) => {}
16 | abTestController.deleteABTest = (req, res, next) => {}
17 | module.exports = abTestController;
18 |
--------------------------------------------------------------------------------
/server/controllers/createDepController.js:
--------------------------------------------------------------------------------
1 | const fetch = require('node-fetch');
2 | const fs = require('fs');
3 |
4 | const token = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', 'utf8');
5 | const body = {
6 | "kind": "Deployment",
7 | "metadata": {
8 | "name": "tiki-taka-rocks-hard",
9 | "labels": {
10 | "app": "reviews",
11 | "version": "v1"
12 | }
13 | },
14 | "spec": {
15 | "replicas": 1,
16 | "selector": {
17 | "matchLabels": {
18 | "app": "reviews",
19 | "version": "v1"
20 | }
21 | },
22 | "template": {
23 | "metadata": {
24 | "labels": {
25 | "app": "reviews",
26 | "version": "v1"
27 | }
28 | },
29 | "spec": {
30 | "serviceAccountName": "bookinfo-reviews",
31 | "containers": [
32 | {
33 | "name": "reviews",
34 | "image": "docker.io/istio/examples-bookinfo-reviews-v1:1.15.0",
35 | "imagePullPolicy": "IfNotPresent",
36 | "ports": [
37 | {
38 | "containerPort": 9080
39 | }
40 | ]
41 | }
42 | ]
43 | }
44 | }
45 | }
46 | };
47 |
48 | const createDepController = {};
49 | process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
50 | createDepController.addVirtualService = (req, res, next) => {
51 | let newIm = {};
52 | const { imageA, weightA, imageB, addressB, versionB } = req.body;
53 | fetch(`https://kubernetes.default.svc/apis/apps/v1/namespaces/default/deployments/reviews-v1`)
54 | .then(data => data.json()).then(json => {newIm = json}).catch(e => console.log(e));
55 |
56 | fetch('https://kubernetes.default.svc/apis/apps/v1/namespaces/default/deployments/', {
57 | method: 'POST',
58 | body: JSON.stringify(body),
59 | requestCert: false,
60 | rejectUnauthorized: false,
61 | headers: { 'Content-Type': 'application/json',
62 | 'Authorization': `Bearer ${token}`
63 | },
64 | ca: [fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt', 'utf8'), fs.readFileSync('/usr/src/app/DigiCertAssuredIDCAG2.crt.pem', 'utf8') ],
65 | })
66 | .then(r => r.json()).then(json => console.log(json)).catch(e => console.log(e));
67 | return next();
68 | };
69 | module.exports = createDepController;
70 |
--------------------------------------------------------------------------------
/server/controllers/historyController.js:
--------------------------------------------------------------------------------
1 | // const { History } = require('../models/historyModels');
2 |
3 | // const historyController = {};
4 |
5 | // historyController.getHistory((req, res, next) => {
6 | // return next();
7 | // });
8 |
9 | // module.exports = historyController;
--------------------------------------------------------------------------------
/server/controllers/testController.js:
--------------------------------------------------------------------------------
1 | const testController = {};
2 | const fetch = require("node-fetch");
3 |
4 | /**
5 | * Sending cluster pods information
6 | */
7 | testController.getData = async (req, res, next) => {
8 | console.log('data');
9 | const url = 'http://localhost:8081/apis/apps/v1/namespaces/default/deployments/'
10 | await fetch(url)
11 | .then (resp => resp.json())
12 | .then (data => {
13 | res.locals.data = data;
14 | console.log(data);
15 | })
16 | .catch (err => console.log(err));
17 | return next();
18 | }
19 |
20 | /**
21 | * testingAB -
22 | */
23 | testController.testingAB = (req, res, next) => {
24 | console.log('ab');
25 | return next();
26 | }
27 |
28 | module.exports = testController;
29 |
--------------------------------------------------------------------------------
/server/controllers/testControllerIstio.js:
--------------------------------------------------------------------------------
1 | const testController = {};
2 |
3 | /**
4 | * Sending cluster pods information
5 | */
6 | testController.setup = (req, res, next) => {
7 | async function main () {
8 | try {
9 | const backend = new Request(Request.config.getInCluster())
10 | const client = new Client({ backend })
11 | await client.loadSpec()
12 |
13 | //
14 | // Fetch the Deployment from cluste
15 | //
16 | const deployment = await client.apis.apps.v1.namespaces('default').deployments().get();
17 | const data = [];
18 | deployment.body.items.forEach((item) => {
19 | data.push(item.metadata);
20 | console.log(item.metadata);
21 | });
22 | res.locals.data = data;
23 | } catch (err) {
24 | res.locals.data = err;
25 | console.error('Error: ', err)
26 | }
27 | next();
28 | }
29 | main();
30 | }
31 |
32 | /**
33 | * testingAB -
34 | */
35 | testController.testingAB = (req, res, next) => {
36 | async function applyDeploy () {
37 | try {
38 | const backend = new Request(Request.config.getInCluster())
39 | const client = new Client({ backend })
40 | await client.loadSpec()
41 |
42 | let opts = {
43 | apiVersion: 'networking.istio.io/v1alpha3',
44 | kind: 'VirtualService',
45 | metadata: {
46 | name: 'bookinfotest',
47 | namespace: 'default'
48 | },
49 | spec: {
50 | gateways:[
51 | 'bookinfo-gateway',
52 | ],
53 | hosts: [
54 | 'holllaaa'
55 | ],
56 | http: [{
57 | route: [
58 | {
59 | destination: {
60 | host: '*',
61 | subset: 'safe'
62 | }
63 | }
64 | ]
65 | }]
66 | }
67 | }
68 | opts = JSON.stringify(opts);
69 | try{
70 | const create = await client.apis['networking.istio.io'].v1alpha3.namespaces('default').virtualservices.post({body:opts})
71 | res.locals.data = create.body;
72 | console.log('Create:', create);
73 | }catch (err){
74 | res.locals.data = err;
75 | }
76 | } catch (err) {
77 | if (err.code !== 409) throw err
78 | }
79 | next();
80 | }
81 | applyDeploy()
82 | }
83 |
84 | module.exports = testController;
--------------------------------------------------------------------------------
/server/models/abTestModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const Schema = mongoose.Schema;
3 |
4 | const abTestSchema = new Schema({
5 | name: {type: String, required: true, unique: true},
6 | //the A Test props
7 | testA: {},
8 | //the B test props would be a list of annotations those are changed from test A
9 | //if a property set here is not present in Test A it should give an error.
10 | //string is chosen as the type of values for predictability
11 | //Todo: handle any different values different than testA has in creation.
12 | //Todo: handle any different values different than testA has on update.
13 | testB: {
14 | type: Map,
15 | of: String
16 | },
17 | archived: Boolean,
18 | active: {type: Boolean, required: true, default: true},
19 | relatedCustomResourceDefinitions: {
20 | type: Map,
21 | //todo: check this if you have to relate to any other Schema
22 | of: [String]
23 | },
24 | relatedServices: [String],
25 | relatedGateways: [String]
26 |
27 |
28 | });
29 |
30 |
31 | module.exports = mongoose.model('abTest', abTestSchema);
32 |
--------------------------------------------------------------------------------
/server/models/historyModels.js:
--------------------------------------------------------------------------------
1 | // 'use strict'
2 | // const mongoose = require('mongoose');
3 | // const Schema = mongoose.Schema;
4 |
5 | // const historySchema = new Schema({
6 | // podAName: { type: String, required: true },
7 | // podAWeight: { type: Number },
8 | // podAContent: { type: String },
9 | // podBName: { type: String, required: true },
10 | // podBWeight: { type: Number },
11 | // podBContent: { type: String },
12 | // createdAt: { type: Date, default: Date.now }
13 | // });
14 |
15 | // const History = mongoose.model('History', historySchema);
16 |
17 | // module.exports = { History };
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const bodyParser = require('body-parser');
3 | const path = require('path');
4 | const testController = require('./controllers/testController');
5 | const createDepController = require('./controllers/createDepController');
6 | // const mongoose = require('mongoose');
7 | // const { History } = require('./models/historyModels');
8 | // const db = require('./config/keys').MONGO_URI;
9 |
10 | // mongoose
11 | // .connect(db, {
12 | // useNewUrlParser: true,
13 | // useUnifiedTopology: true,
14 | // dbName: 'tikitaka'
15 | // })
16 | // .then(() => console.log('Connected to mongoDB'))
17 | // .catch(err => console.log(err));
18 |
19 | const app = express();
20 |
21 | const PORT = process.env.PORT || '3000';
22 |
23 | app.use(bodyParser.json());
24 | app.use(bodyParser.urlencoded({ extended: true }));
25 | app.use(express.static(path.join(__dirname, '../build/')));
26 |
27 | // app.get('/getDeploys',testController.setup, (req,res) => {
28 | // res.json(res.locals.data);
29 | // });
30 | // app.get('/testing-ab',testController.testingAB, (req,res) => {
31 | // res.json(res.locals.data);
32 | // });
33 | app.all('/dothis', createDepController.addVirtualService, (req, res) => {
34 | return res.json('do it please please');
35 | });
36 |
37 | // app.get('/history', (req, res) => {
38 | // History.find({})
39 | // .exec()
40 | // .then(docs => {
41 | // res.status(200).json(docs)
42 | // });
43 | // });
44 |
45 | // app.post('/history', (req, res) => {
46 | // console.log(req.body);
47 | // History.create({
48 | // podAName: 'cat',
49 | // podAWeight: 33,
50 | // podAContent: '',
51 | // podBName: 'dog',
52 | // podBWeight: 67,
53 | // podBContent: '',
54 | // createdAt: Date.now()
55 | // });
56 | // });
57 |
58 | /**
59 | * 404 handler for any request to unknown routes
60 | */
61 | app.use('*',(req,res) => {
62 | res.sendStatus(404);
63 | });
64 |
65 | /**
66 | * Global error handler
67 | */
68 | app.use((err, req, res, next) => {
69 | // console.error(err.stack);
70 | // Creating our default error
71 | const defaulErr = {
72 | log: 'Express error handler caught unknown middleware error',
73 | status: 400,
74 | message: { err: 'An error ocurred'},
75 | };
76 | const errorObj = Object.assign(defaulErr, err);
77 | console.log(errorObj.log);
78 | res.status(errorObj.status).json(errorObj.message);
79 | });
80 |
81 | app.listen(PORT, () => {
82 | console.log(`Server listening on port: ${PORT}`);
83 | });
84 |
--------------------------------------------------------------------------------
/skaffold.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: skaffold/v2alpha3
2 | kind: Config
3 | metadata:
4 | name: istio-ab-testing
5 | build:
6 | artifacts:
7 | - image: tikitaka1/tikitaka-stage
8 | deploy:
9 | kubectl:
10 | manifests:
11 | - k8s/tikitaka-app.yaml
12 |
--------------------------------------------------------------------------------
/src/assets/IMG_9802.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Tikitaka/2e97fbb94890e95a831a101d88628cb1d95d1d6c/src/assets/IMG_9802.png
--------------------------------------------------------------------------------
/src/assets/deployment.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "apps/v1",
3 | "kind": "Deployment",
4 | "metadata": {
5 | "name": "NAMEOFTHEDEPLOYMENT",
6 | "labels": {
7 | "version": "v1"
8 | }
9 | },
10 | "spec": {
11 | "replicas": 1,
12 | "selector": {
13 | "matchLabels": {
14 | "app": "NAMEOFAPP"
15 | }
16 | },
17 | "template": {
18 | "metadata": {
19 | "labels": {
20 | "app": "NAMEOFAPP",
21 | "version": "v1"
22 | }
23 | }
24 | },
25 | "spec": {
26 | "containers":[
27 | {
28 | "name": "NAMEOFAP",
29 | "image": "IMAGESOURCE",
30 | "ports": [
31 | {
32 | "containerPort": 3000
33 | }
34 | ],
35 | "imagePullPolicy": "Always"
36 | }
37 | ]
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/assets/destinationrules.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "networking.istio.io/v1alpha3",
3 | "kind": "DestinationRule",
4 | "metadata": {
5 | "name": "DESTINATIONNAME",
6 | "namespace": "default"
7 | },
8 | "spec": {
9 | "host": "NAMESERVICE",
10 | "trafficPolicy": null,
11 | "subsets": [
12 | {
13 | "name": "safe",
14 | "labels": {
15 | "version": "safe"
16 | }
17 | },
18 | {
19 | "name": "test",
20 | "labels": {
21 | "version": "test"
22 | }
23 | }
24 | ]
25 | }
26 | }
--------------------------------------------------------------------------------
/src/assets/gateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "networking.istio.io/v1alpha3",
3 | "kind": "Gateway",
4 | "metadata": {
5 | "name": "GATEWAYNAME"
6 | },
7 | "spec": {
8 | "selector": {
9 | "istio": "ingressgateway"
10 | },
11 | "servers": [
12 | {
13 | "port": {
14 | "number": 80,
15 | "name": "http",
16 | "protocol": "HTTP"
17 | },
18 | "hosts": [
19 | "*"
20 | ]
21 | }
22 | ]
23 | }
24 | }
--------------------------------------------------------------------------------
/src/assets/github-resume.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Tikitaka/2e97fbb94890e95a831a101d88628cb1d95d1d6c/src/assets/github-resume.jpg
--------------------------------------------------------------------------------
/src/assets/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Tikitaka/2e97fbb94890e95a831a101d88628cb1d95d1d6c/src/assets/img1.png
--------------------------------------------------------------------------------
/src/assets/mario.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Tikitaka/2e97fbb94890e95a831a101d88628cb1d95d1d6c/src/assets/mario.png
--------------------------------------------------------------------------------
/src/assets/service.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "v1",
3 | "kind": "Service",
4 | "metadata": {
5 | "name": "NAMEOFTHESERVICE",
6 | "labels": {
7 | "app": "NAMEOFTHEAPP"
8 | }
9 | },
10 | "spec": {
11 | "selector": {
12 | "app": "NAMEOFTHEAPP"
13 | },
14 | "ports": [
15 | {
16 | "name": "http",
17 | "port": 3000
18 | }
19 | ]
20 | }
21 | }
--------------------------------------------------------------------------------
/src/assets/virtualservice.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "networking.istio.io/v1alpha3",
3 | "kind": "VirtualService",
4 | "metadata": {
5 | "name": "NAMEOFTHEVIRTUAL",
6 | "namespace": "default"
7 | },
8 | "spec": {
9 | "gateways":[
10 | "NAMEOFGATEWAY"
11 | ],
12 | "hosts": [
13 | "*"
14 | ],
15 | "http": [{
16 | "route": [
17 | {
18 | "destination": {
19 | "host": "*",
20 | "subset": "safe"
21 | },
22 | "weight": 50
23 | },
24 | {
25 | "destination": {
26 | "host": "*",
27 | "subset": "test"
28 | },
29 | "weight": 50
30 | }
31 | ]
32 | }]
33 | }
34 | }
--------------------------------------------------------------------------------
/src/components/About.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | interface Iprops{
4 |
5 | }
6 |
7 | export default class TestForm extends React.Component{
8 | public render(): JSX.Element{
9 | return(
10 |
11 |
12 |
13 |

14 |
15 |
16 |
Arman Gurkan
17 |
Baby lover
18 |
19 |

20 |

21 |
22 |
23 |
24 |
25 |
26 |
27 |

28 |
29 |
30 |
Jie-Yun Catherine Cheng
31 |
Cat lover
32 |
33 |

34 |

35 |
36 |
37 |
38 |
39 |
40 |
41 |

42 |
43 |
44 |
Pati Honores
45 |
Dog lover
46 |
47 |

48 |

49 |
50 |
51 |
52 |
53 |
54 |
55 |

56 |
57 |
58 |
Ryan SukWoo Kim
59 |
Song lover
60 |
61 |

62 |

63 |
64 |
65 |
66 |
67 |
68 |
69 |

70 |
71 |
72 |
Yunho Cho
73 |
Code Life
74 |
75 |

76 |

77 |
78 |
79 |
80 |
81 | )
82 | }
83 | }
--------------------------------------------------------------------------------
/src/components/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {Container, Row, Col} from 'react-bootstrap';
3 | import Navbar from 'react-bootstrap/Navbar';
4 | import Nav from 'react-bootstrap/Nav';
5 | import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
6 | import Bullets from './Bullets';
7 | import Sidebar from './Sidebar';
8 | import TestForm from './TestForm';
9 | import About from './About';
10 | import TestDisplay from './TestDisplay';
11 | import { HistoryProvider } from '../context/historyContext';
12 |
13 | //===================================================================================================//
14 | // INTERFACE //
15 | //===================================================================================================//
16 | // Typescript: because states are given, need to define as interface
17 | interface IState
18 | {
19 | currentWindow: String;
20 | }
21 |
22 | //
23 | export class App extends React.Component<{}, IState>{
24 | //===================================================================================================//
25 | // CONSTRUCTOR //
26 | //===================================================================================================//
27 | constructor(props: {}) {
28 | super(props);
29 |
30 | // Defining state
31 | this.state = {
32 | currentWindow:"home"
33 | }
34 | }
35 | //===================================================================================================//
36 | // METHODS //
37 | //===================================================================================================//
38 |
39 | //=============================================PUBLIC
40 | // public handleSubmit(e: React.FormEvent): void{
41 | // // Type of e is called = React.FormEvent
42 | // e.preventDefault();
43 | // this.setState({
44 | // currentTask: "",
45 | // tasks: [
46 | // ...this.state.tasks,
47 | // {
48 | // id: this._timeInMilliseconds(),
49 | // value: this.state.currentTask,
50 | // completed: false
51 | // }
52 | // ]
53 | // })
54 | // }
55 |
56 | // public deleteTask(taskId: number): void {
57 | // const filteredTask: Array = this.state.tasks.filter(
58 | // (task: ITask) => task.id !== taskId
59 | // );
60 | // this.setState({tasks: filteredTask});
61 | // }
62 |
63 | // public toggleDone(index: number): void {
64 | // let task: ITask[] = this.state.tasks.splice(index, 1);
65 | // task[0].completed = !task[0].completed;
66 | // const tasks: ITask[] = [...this.state.tasks, ...task];
67 | // this.setState({tasks});
68 | // }
69 |
70 | // public renderTasks(): JSX.Element[] {
71 | // return this.state.tasks.map((task: ITask, index: number) => {
72 | // return (
73 | //
75 | // {task.value}
76 | //
77 | //
78 | //
79 | // )
80 | // })
81 | // }
82 | //===================================================================================================//
83 | // RENDER //
84 | //===================================================================================================//
85 | public render(): JSX.Element{
86 | return (
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | Welcome
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | TIKITAKA
105 |
106 |
107 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | );
142 | }
143 |
144 |
145 | //=============================================PRIVATE
146 | // private _timeInMilliseconds(): number {
147 | // const date: Date = new Date();
148 | // return date.getTime();
149 | // }
150 | }
151 |
--------------------------------------------------------------------------------
/src/components/Bullets.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Group } from '@vx/group';
3 | import { Tree } from '@vx/hierarchy';
4 | import { LinearGradient } from '@vx/gradient';
5 | import { hierarchy } from 'd3-hierarchy';
6 | import { pointRadial } from 'd3-shape';
7 | // import data from './Data';
8 |
9 |
10 | import {
11 | LinkHorizontal,
12 | LinkVertical,
13 | LinkRadial,
14 | LinkHorizontalStep,
15 | LinkVerticalStep,
16 | LinkRadialStep,
17 | LinkHorizontalCurve,
18 | LinkVerticalCurve,
19 | LinkRadialCurve,
20 | LinkHorizontalLine,
21 | LinkVerticalLine,
22 | LinkRadialLine
23 | } from '@vx/shape';
24 |
25 | // @Pati, @Ryan TODO: this constant json has to be fetched from the backend
26 | const json: any = [{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"1fbb77f8a48f052a","id":"70028bc7b7f58a23","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321633826,"duration":14387,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"6c7d4c9563f118aa","id":"ac6d1225d090ceba","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321631938,"duration":18843,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"65b6b12e14496a0b","id":"0ac9e828af6c26e7","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321636640,"duration":25915,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"6c7d4c9563f118aa","id":"81b0093f2ef24d46","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321652339,"duration":14573,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"65b6b12e14496a0b","id":"b569b61faa18d09f","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321636329,"duration":23881,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"1fbb77f8a48f052a","id":"6ca93a585e73d737","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321649933,"duration":25618,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"65b6b12e14496a0b","id":"b4993d57e8bfb02d","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321661963,"duration":30949,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"1fbb77f8a48f052a","id":"701d41c2a814e088","kind":"CLIENT","name":"get /backend","timestamp":1580415321634189,"duration":61127,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"8080","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"701d41c2a814e088","id":"65b6b12e14496a0b","kind":"SERVER","name":"get /backend","timestamp":1580415321635074,"duration":57367,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.route":"/backend","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","http.user_agent":"axios/0.19.2","net.host.ip":"::ffff:127.0.0.1","net.host.name":"localhost","net.host.port":"8080","net.peer.ip":"::ffff:127.0.0.1","net.peer.port":"59793","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"65b6b12e14496a0b","id":"6bbd0e9e2e60ab06","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321665660,"duration":24684,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"41510564ad7c6bfd","id":"7839dfc70cc40bb4","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321697071,"duration":8282,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"41510564ad7c6bfd","id":"a16aab873555210f","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321697331,"duration":9938,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"41510564ad7c6bfd","id":"027c15ee6d4111f3","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321706800,"duration":9753,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"41510564ad7c6bfd","id":"0fc40aac3028665f","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321708606,"duration":12115,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"1fbb77f8a48f052a","id":"98d9f024cf0a13cf","kind":"CLIENT","name":"get /backend","timestamp":1580415321695763,"duration":27396,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"8080","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"98d9f024cf0a13cf","id":"41510564ad7c6bfd","kind":"SERVER","name":"get /backend","timestamp":1580415321696658,"duration":25746,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.route":"/backend","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","http.user_agent":"axios/0.19.2","net.host.ip":"::ffff:127.0.0.1","net.host.name":"localhost","net.host.port":"8080","net.peer.ip":"::ffff:127.0.0.1","net.peer.port":"59810","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"6c7d4c9563f118aa","id":"600376586b3d82e0","kind":"CLIENT","name":"get /middle-tier","timestamp":1580415321632257,"duration":92833,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/middle-tier","http.url":"http://localhost:8080/middle-tier","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"8080","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"600376586b3d82e0","id":"1fbb77f8a48f052a","kind":"SERVER","name":"get /middle-tier","timestamp":1580415321633363,"duration":91019,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.route":"/middle-tier","http.status_code":"200","http.status_text":"OK","http.target":"/middle-tier","http.url":"http://localhost:8080/middle-tier","http.user_agent":"axios/0.19.2","net.host.ip":"::ffff:127.0.0.1","net.host.name":"localhost","net.host.port":"8080","net.peer.ip":"::ffff:127.0.0.1","net.peer.port":"59790","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"798341b81e0957fb","id":"dc22ebafb6bf6c0d","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321726968,"duration":26575,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"8083f844a54532aa","id":"4989998b12c862b2","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321729038,"duration":19346,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"8083f844a54532aa","id":"3f80161fab04fe24","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321728774,"duration":22664,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"3190e8d818239c3a","id":"8083f844a54532aa","kind":"SERVER","name":"get /backend","timestamp":1580415321728259,"duration":39000,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.route":"/backend","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","http.user_agent":"axios/0.19.2","net.host.ip":"::ffff:127.0.0.1","net.host.name":"localhost","net.host.port":"8080","net.peer.ip":"::ffff:127.0.0.1","net.peer.port":"59824","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"8083f844a54532aa","id":"4843ede811d77635","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321752874,"duration":20371,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"798341b81e0957fb","id":"ed4bcc1944d99c24","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321754991,"duration":12854,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"798341b81e0957fb","id":"3190e8d818239c3a","kind":"CLIENT","name":"get /backend","timestamp":1580415321727229,"duration":45129,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:8080","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/backend","http.url":"http://localhost:8080/backend","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"8080","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"8083f844a54532aa","id":"cb3bed81ea2eb9b6","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321750126,"duration":15171,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"b37f6ce85e7a502e","id":"17e37d937c577652","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321778382,"duration":19183,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}},{"traceId":"f8a0f44e7cef050b4e8767cc370e1cc5","parentId":"b37f6ce85e7a502e","id":"826a29e7acb3b350","kind":"CLIENT","name":"get /zipkin/api/v2/traces","timestamp":1580415321778114,"duration":17364,"localEndpoint":{"serviceName":"getting-started"},"tags":{"component":"http","http.flavor":"1.1","http.host":"localhost:9411","http.method":"GET","http.status_code":"200","http.status_text":"OK","http.target":"/zipkin/api/v2/traces","http.url":"http://localhost:9411/zipkin/api/v2/traces","net.peer.ip":"127.0.0.1","net.peer.name":"localhost","net.peer.port":"9411","net.transport":"IP.TCP","ot.status_code":"OK"}}];
27 |
28 | interface TrimmedDownJson {
29 | index: number;
30 | traceId: string;
31 | parentId: string;
32 | id: string;
33 | }
34 |
35 | const trimmedDownJson: Array = [];
36 | json.forEach((trace: any, index: number) => {
37 | const { traceId, parentId, id } = trace;
38 | trimmedDownJson.push({
39 | index,
40 | traceId,
41 | parentId,
42 | id
43 | });
44 | });
45 | // console.log('trimmedDownJson: ', trimmedDownJson);
46 |
47 | const parentId: Array = trimmedDownJson.map(trace => trace.parentId);
48 | // console.log('parentId: ', parentId);
49 |
50 | const id: Array = trimmedDownJson.map(trace => trace.id);
51 | // console.log('id: ', id);
52 |
53 | interface Relationship {
54 | parentId: string;
55 | parentIndex: number;
56 | childrenId: string;
57 | childIndex: number;
58 | }
59 |
60 | const relationships: Array = [];
61 | id.forEach((id, parentIndex) => {
62 | if (parentId.includes(id)) {
63 | // console.log('parent id: ', id, 'at index: ', parentIndex);
64 | const childIndex = parentId.findIndex(parentId => parentId === id);
65 | // console.log('child id: ', trimmedDownJson[childIndex].id, 'at index: ', childIndex);
66 | relationships.push({ parentId: id, parentIndex, childrenId: trimmedDownJson[childIndex].id, childIndex });
67 | }
68 | });
69 | // console.log('relationships: ', relationships);
70 |
71 | interface Node {
72 | name: string;
73 | children?: Node[];
74 | }
75 |
76 | const nodes: Array = [];
77 | id.forEach(id => {
78 | nodes.push({name: id});
79 | });
80 |
81 | relationships.forEach(relationship => {
82 | if (nodes[relationship.parentIndex].children) {
83 | nodes[relationship.parentIndex].children.push(nodes[relationship.childIndex]);
84 | } else {
85 | nodes[relationship.parentIndex].children = [nodes[relationship.childIndex]];
86 | }
87 | });
88 | // console.log('nodes: ', nodes);
89 |
90 | relationships.map(relationship => relationship.childIndex).sort((a, b) => a - b).reverse().forEach(childIndex => nodes.splice(childIndex, 1));
91 | // console.log('after deleting duplicate nodes: ', nodes);
92 |
93 | interface Data {
94 | [x: string]: any;
95 | name: string;
96 | children?: Data[];
97 | }
98 | const data: Data = {
99 | name: trimmedDownJson[0].traceId,
100 | children: nodes
101 | };
102 | // console.log('data: ', data);
103 |
104 | // const data:Data = {
105 | // name: 'HOST',
106 | // children: [
107 | // {
108 | // name: 'IP1',
109 | // children: [
110 | // { name: 'AAsasasasasas1' },
111 | // { name: 'A2' },
112 | // { name: 'A3' },
113 | // {
114 | // name: 'C',
115 | // children: [
116 | // {
117 | // name: 'C1'
118 | // },
119 | // {
120 | // name: 'D',
121 | // children: [
122 | // {
123 | // name: 'D1',
124 | // children: [
125 | // {
126 | // name: 'D1'
127 | // },
128 | // {
129 | // name: 'D2'
130 | // },
131 | // {
132 | // name: 'D3'
133 | // }
134 | // ]
135 | // },
136 | // {
137 | // name: 'D2'
138 | // },
139 | // {
140 | // name: 'D3'
141 | // }
142 | // ]
143 | // }
144 | // ]
145 | // }
146 | // ]
147 | // },
148 | // { name: 'Z' },
149 | // {
150 | // name: 'B',
151 | // children: [{ name: 'B1' }, { name: 'B2' }, { name: 'B3' }]
152 | // }
153 | // ]
154 | // };
155 | interface Iprops {
156 | width: number;
157 | height: number;
158 | margin: any;
159 | }
160 |
161 | export default class Bullets extends React.Component {
162 | state = {
163 | layout: 'cartesian',
164 | orientation: 'horizontal',
165 | linkType: 'diagonal',
166 | stepPercent: 0.5
167 | };
168 |
169 | render() {
170 | const {
171 | width,
172 | height,
173 | margin = {
174 | top: 30,
175 | left: 30,
176 | right: 30,
177 | bottom: 30
178 | }
179 | } = this.props;
180 |
181 | const { layout, orientation, linkType, stepPercent } = this.state;
182 |
183 | const innerWidth = width - margin.left - margin.right;
184 | const innerHeight = height - margin.top - margin.bottom;
185 |
186 | let origin: { y: any; x: any; };
187 | let sizeWidth;
188 | let sizeHeight;
189 |
190 | if (layout === 'polar') {
191 | origin = {
192 | x: innerWidth / 2,
193 | y: innerHeight / 2
194 | };
195 | sizeWidth = 2 * Math.PI;
196 | sizeHeight = Math.min(innerWidth, innerHeight) / 2;
197 | } else {
198 | origin = { x: 0, y: 0 };
199 | if (orientation === 'vertical') {
200 | sizeWidth = innerWidth;
201 | sizeHeight = innerHeight;
202 | } else {
203 | sizeWidth = innerHeight;
204 | sizeHeight = innerWidth;
205 | }
206 | }
207 |
208 | return (
209 |
210 |
211 |
212 |
220 |
221 |
222 |
231 |
232 |
233 |
243 |
244 |
245 | e.stopPropagation()}
247 | type="range"
248 | min={0}
249 | max={1}
250 | step={0.1}
251 | onChange={e => this.setState({ stepPercent: e.target.value })}
252 | value={stepPercent}
253 | disabled={linkType !== 'step' || layout === 'polar'}
254 | />
255 |
256 |
257 |
390 |
391 | );
392 | }
393 | }
--------------------------------------------------------------------------------
/src/components/FetcherComponent.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState, useEffect } from 'react';
3 | const opt = {
4 | "apiVersion": "networking.istio.io/v1alpha3",
5 | "kind": "VirtualService",
6 | "metadata": {
7 | "name": "tikitaka"
8 | },
9 | "spec": {
10 | "hosts": [
11 | "*"
12 | ],
13 | "gateways": [
14 | "tikitaka-gateway"
15 | ],
16 | "http": [
17 | {
18 | "route": [
19 | {
20 | "destination": {
21 | "host": "tikitaka"
22 | }
23 | }
24 | ]
25 | }
26 | ]
27 | }
28 | };
29 | const Fetcher: React.FC = props => {
30 | const [virtualServices, addVirtualService] = useState([]);
31 | const getContainers = async () => {
32 | let response = await fetch('http://localhost:8081/apis/apps/v1/namespaces/default/deployments/',{
33 | method: 'POST',
34 | body: JSON.stringify(opt)
35 | });
36 | let vS = await response.json();
37 | addVirtualService([...virtualServices, vS]);
38 | };
39 | useEffect(() => {getContainers()}
40 | , []);
41 | const result: any[] = [...virtualServices];
42 | return (
43 |
44 | {result}
45 |
46 | )
47 | };
48 |
49 | export default Fetcher;
50 |
--------------------------------------------------------------------------------
/src/components/Sidebar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState, useEffect } from 'react';
3 | import Form from 'react-bootstrap/Form'
4 | import { Col, Row } from 'react-bootstrap';
5 | import Button from 'react-bootstrap/Button'
6 | import InputGroup from 'react-bootstrap/InputGroup'
7 | interface Iprops{
8 | };
9 | interface ReqOptions {
10 | method: string;
11 | headers: any;
12 | body: any;
13 | redirect: any;
14 | }
15 | const myHeaders = new Headers();
16 | myHeaders.append("Content-Type", "application/json");
17 | const vS = JSON.stringify({"apiVersion":"networking.istio.io/v1alpha3","kind":"VirtualService","metadata":{"annotations":{},"name":"aaa-cluster-ip-service","namespace":"default"},"spec":{"gateways":["ingress-gateway-configuration"],"hosts":["*"],"http":[{"match":[{"uri":{"prefix":"/topitop"}}],"route":[{"destination":{"host":"arman-cluster-ip-service"}}]},{"match":[{"uri":{"prefix":"/taksi"}}],"route":[{"destination":{"host":"client-cluster-ip-service","subset":"original"},"weight":90},{"destination":{"host":"client-cluster-ip-service","subset":"experimental"},"weight":10}]}]}});
18 | const reqOption:ReqOptions = {
19 | method: 'POST',
20 | headers: myHeaders,
21 | body: vS,
22 | redirect: 'follow'
23 | };
24 |
25 |
26 |
27 | const TestForm: React.FC = () => {
28 | interface eachMetadataType {
29 | name: string;
30 | namespace: string;
31 | selfLink: string;
32 | uid: string;
33 | resourceVersion: string;
34 | generation: number;
35 | creationTimestamp: string;
36 | }
37 | interface eachItemType {
38 | metadata: eachMetadataType;
39 | spec: object;
40 | status: object;
41 | }
42 | interface containersType {
43 | kind: string;
44 | apiVersion: string;
45 | metadata: object;
46 | items: eachItemType[];
47 | }
48 | const [containers, setContainers] = useState({
49 | kind: '',
50 | apiVersion: '',
51 | metadata: {},
52 | items: [{metadata: {name: "api-gateway",
53 | namespace: "default",
54 | selfLink: "/apis/apps/v1/namespaces/default/deployments/api-gateway",
55 | uid: "2ad6806d-0071-45cc-929f-09da9d21a9c9",
56 | resourceVersion: "116386",
57 | generation: 1,
58 | creationTimestamp: "2020-02-10T20:01:48Z"}, spec: {}, status: {}}]
59 | });
60 | // useEffect(() => {
61 | // const getContainers = async () => {
62 | // let r = await fetch('http://localhost:8001/apis/apps/v1/namespaces/default/deployments/');
63 | // let containers = await r.json();
64 | // setContainers(containers);
65 | // };
66 | // getContainers();
67 | // },[]);
68 | const dropDown = [];
69 | if (containers.items.length > 1) {
70 | for(let i = 0; i < containers.items.length; i++) {
71 | let list =
72 | dropDown.push(list)
73 | }
74 | } else {
75 | dropDown.push();
76 | }
77 |
78 |
79 | useEffect(() => {
80 | const addVirtualService = async () => {
81 | let r = await fetch('/dothis');
82 | let c = await r.json();
83 | console.log(c);
84 | };
85 | addVirtualService();
86 | },[]);
87 | return (
88 |
90 |
91 | Docker Image A:
92 |
93 | {dropDown}
94 |
95 |
96 |
97 |
101 |
102 | %
103 | weight
104 |
105 |
106 |
107 |
108 | Docker Image B:
109 |
110 |
111 | Name:
112 |
113 |
117 |
118 |
119 |
120 |
121 | Address:
122 |
123 |
128 |
129 |
130 |
131 |
132 | Version:
133 |
134 |
139 |
140 |
141 |
142 |
143 |
146 |
149 |
150 | );
151 | }
152 | export default TestForm;
153 |
--------------------------------------------------------------------------------
/src/components/TestDisplay.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useContext } from 'react';
3 | import Carousel from 'react-bootstrap/Carousel';
4 | import { HistoryContext } from '../context/historyContext';
5 |
6 | interface Iprops{}
7 |
8 | const TestDisplay: React.FC = () => {
9 | const { history } = useContext(HistoryContext);
10 | console.log('history from testdisplay component', history);
11 |
12 | const srcImg = ["https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQsr2CnfzB8gKPvCCLwe3AQTTleO4k2QRq4T7L35lWF7djy8RFy",
13 | 'https://graniteworx.com/wp-content/uploads/2015/01/Absolute-Black-INDIA1-400x400.jpg',
14 | "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEXukY3/VYS2AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC",
15 | "https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcS4QPHeQXFYFZG7vzBj7jtyvXkK9g2GCWxvRCvtrPCraKTv6iKs"];
16 |
17 | const carousel = [];
18 | for(let i = 0; i < history.length; i++) {
19 | carousel.push(
20 |
21 |
26 |
27 | image A: {`${history[i].imageA}`}
28 | weight A: {`${history[i].weightA}`}
29 | image B: {`${history[i].imageB}`}
30 | address B: {`${history[i].addressB}`}
31 | version B: {`${history[i].versionB}`}
32 |
33 |
34 | );
35 | }
36 | return(
37 |
38 | {carousel}
39 |
40 | )
41 | }
42 |
43 | export default TestDisplay;
--------------------------------------------------------------------------------
/src/components/TestForm.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState, useEffect, useContext, createContext } from 'react';
3 | import { Col, Row } from 'react-bootstrap';
4 | import Form from 'react-bootstrap/Form';
5 | import Button from 'react-bootstrap/Button';
6 | import InputGroup from 'react-bootstrap/InputGroup';
7 | import { HistoryContext } from '../context/historyContext';
8 |
9 | interface Iprops{};
10 |
11 | const TestForm: React.FC = (props) => {
12 | const { history, setHistory } = useContext(HistoryContext);
13 | interface eachMetadataType {
14 | name: string;
15 | namespace: string;
16 | selfLink: string;
17 | uid: string;
18 | resourceVersion: string;
19 | generation: number;
20 | creationTimestamp: string;
21 | };
22 | interface eachItemType {
23 | metadata: eachMetadataType;
24 | spec: object;
25 | status: object;
26 | };
27 | interface containersType {
28 | kind: string;
29 | apiVersion: string;
30 | metadata: object;
31 | items: eachItemType[];
32 | };
33 | const [containers, setContainers] = useState({
34 | kind: '',
35 | apiVersion: '',
36 | metadata: {},
37 | items: [{metadata: {name: "api-gateway",
38 | namespace: "default",
39 | selfLink: "/apis/apps/v1/namespaces/default/deployments/api-gateway",
40 | uid: "2ad6806d-0071-45cc-929f-09da9d21a9c9",
41 | resourceVersion: "116386",
42 | generation: 1,
43 | creationTimestamp: "2020-02-10T20:01:48Z"}, spec: {}, status: {}}]
44 | });
45 | const getContainers = async () => {
46 | const r = await fetch('http://localhost:8081/apis/apps/v1/namespaces/default/deployments/');
47 | const containers = await r.json();
48 | setContainers(containers);
49 | };
50 | useEffect(() => {getContainers()}, []);
51 | const dropDown = [];
52 | if (containers.items.length > 1) {
53 | for(let i = 0; i < containers.items.length; i++) {
54 | dropDown.push();
55 | }
56 | } else {
57 | dropDown.push();
58 | dropDown.push();
59 | dropDown.push();
60 | }
61 |
62 | /////////////
63 | // button //
64 | ////////////
65 | interface arrayType {
66 | nameA: string;
67 | weightA: number;
68 | nameB: string;
69 | addressB: string;
70 | versionB: string;
71 | };
72 |
73 | const [imageA, setImageA] = useState('');
74 | const dropdownHandler = (e:any) =>{
75 | setImageA(e.target.value);
76 | console.log(e.target.value)
77 | };
78 | const [weightA, setWeightA] = useState(0);
79 | const weightAHandler = (e:any) => {
80 | setWeightA(e.target.value);
81 | console.log(weightA);
82 | };
83 |
84 | const [imageB, setImageB] = useState('');
85 | const imageHandler = (e:any) => {
86 | setImageB(e.target.value);
87 | console.log(imageB);
88 | };
89 |
90 | const [addressB, setAddressB] = useState('');
91 | const addressHandler = (e:any) => {
92 | setAddressB(e.target.value);
93 | console.log(addressB);
94 | };
95 |
96 | const [versionB, setVersionB] = useState('');
97 | const versionHandler = (e:any) => {
98 | setVersionB(e.target.value);
99 | console.log(versionB)
100 | };
101 |
102 |
103 | interface ITheme {
104 | Aimage: string,
105 | Aweight: number,
106 | Bimage: string,
107 | Baddress: string,
108 | Bversion: string,
109 | };
110 |
111 | // The standard way to create context. It takes an initial value object
112 | const ThemeContext = createContext({
113 | Aimage: imageA,
114 | Aweight: weightA,
115 | Bimage: imageB,
116 | Baddress: addressB,
117 | Bversion: versionB,
118 | });
119 |
120 | // Accessing context in a child component
121 | const themeContext = useContext(ThemeContext);
122 |
123 | const handleSubmit = (e:any) => {
124 | e.preventDefault();
125 | console.log('successfully bound handleSubmit to the button');
126 | // console.log('request context', requestContext);
127 | // const req = useContext(requestContext.imageA)
128 | // console.log('req', req);
129 | fetch('/dothis').then(data => data.json()).then(json => console.log(json)).catch(e => console.log(e));
130 | setHistory([...history, { imageA, weightA, imageB, addressB, versionB }]);
131 | };
132 | console.log('history now: ', history);
133 |
134 | return (
135 |
136 |
137 |
139 |
140 | Docker Image A:
141 | {dropdownHandler(e)}}>
142 |
143 | {dropDown}
144 |
145 |
146 |
147 |
152 |
153 | %
154 | weight
155 |
156 |
157 |
158 |
159 | Docker Image B:
160 |
161 |
162 | Name:
163 |
164 |
169 |
170 |
171 |
172 |
173 | Address:
174 |
175 |
181 |
182 |
183 |
184 |
185 | Version:
186 |
187 |
193 |
194 |
195 |
196 |
197 | {/* */}
200 |
201 |
202 |
203 | );
204 | };
205 | export default TestForm;
206 |
--------------------------------------------------------------------------------
/src/context/historyContext.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { createContext, useState } from 'react';
3 | export const HistoryContext = createContext(null);
4 |
5 | export const HistoryProvider = (props: any) => {
6 | const [history, setHistory] = useState([{
7 | imageA: 'exampleNameA',
8 | weightA: 100,
9 | imageB: 'exampleNameB',
10 | addressB: '7AB0035',
11 | versionB: '1.0.2'
12 | }]);
13 |
14 | return (
15 |
16 | {props.children}
17 |
18 | )
19 | };
20 |
21 | interface tikitakaContextType {
22 | imageA: string;
23 | weightA: number;
24 | imageB: string;
25 | addressB: string;
26 | versionB: string;
27 | }
28 |
29 | export const TikitakaContext = createContext({
30 | imageA: 'skskskssk',
31 | weightA: 0,
32 | imageB: '',
33 | addressB: '',
34 | versionB: ''
35 | });
36 |
--------------------------------------------------------------------------------
/src/context/tikitakaContext.tsx:
--------------------------------------------------------------------------------
1 | import React, {createContext, useState} from 'react';
2 | export const tikitakaContext = createContext([]);
3 |
4 |
5 | const request = {
6 | imageA: 'skskskssk',
7 | weightA: 0,
8 | imageB: '',
9 | addressB: '',
10 | versionB: ''
11 | }
12 |
13 | export const requestContext = createContext(request)
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import { App } from "./components/App"
4 | import "./styles/app.scss"
5 |
6 | ReactDOM.render(
7 | ,
8 | document.querySelector('.root')
9 | );
--------------------------------------------------------------------------------
/src/styles/app.scss:
--------------------------------------------------------------------------------
1 |
2 | /* RESETS
3 |
4 | ============================================ */
5 |
6 | html {
7 | -webkit-box-sizing: border-box;
8 | box-sizing: border-box;
9 | }
10 | *, *:before, *:after {
11 | -webkit-box-sizing: inherit;
12 | box-sizing: inherit;
13 | }
14 |
15 | body {
16 | margin: 20px 0;
17 | padding-left: 232px;
18 | line-height: 1;
19 | font-family: 'Roboto', sans-serif;
20 | color: #202020;
21 | background-color: #fbfbfb;
22 | -webkit-font-smoothing: antialiased;
23 | -moz-osx-font-smoothing: grayscale;
24 | }
25 |
26 | body{
27 | padding-top:90px
28 | }
29 |
30 | @media (min-width:768px){
31 | body{padding-top:0}
32 | }
33 |
34 | @media (min-width:768px){
35 | body{margin-left:232px;
36 | }
37 | }
38 |
39 | .navbar.fixed-left{
40 | position:fixed;
41 | top:0;
42 | left:0;
43 | right:0;
44 | z-index:1030;
45 | }
46 |
47 | a{
48 | color: rgba(255, 255, 255, 0.5) !important;
49 | padding-right: 0.5rem;
50 | padding-left: 0.5rem;
51 | padding: 0.5rem 1rem !important;
52 | }
53 |
54 | .flex-container{
55 | display: flex;
56 | align-items: center;
57 | justify-content: flex-start;
58 | }
59 |
60 | .thumbnail img{
61 | overflow: hidden;
62 | width: 180px;
63 | height: 180px;
64 | position: relative;
65 | overflow: hidden;
66 | border: 1px solid black;
67 | border-radius: 50%;
68 | }
69 |
70 | .caption .githubIcon{
71 | padding-top: 0.45px;
72 | width: 60px;
73 | }
74 |
75 | .caption .linkedinIcon{
76 | width: 46px;
77 | }
78 |
79 | @media (min-width:768px){
80 | .navbar.fixed-left{
81 | bottom:0;
82 | width:232px;
83 | flex-flow:column nowrap;
84 | align-items:flex-start;
85 | }
86 | .navbar.fixed-left .navbar-collapse{
87 | flex-grow:0;
88 | flex-direction:column;
89 | width:100%
90 | }
91 | .navbar.fixed-left .navbar-collapse .navbar-nav{
92 | flex-direction:column;
93 | width:100%
94 | }.navbar.fixed-left .navbar-collapse .navbar-nav .nav-item{
95 | width:100%
96 | }.navbar.fixed-left .navbar-collapse .navbar-nav .nav-item .dropdown-menu{
97 | top:0
98 | }
99 | }
100 |
101 | @media (min-width:768px){
102 | .navbar.fixed-left{
103 | right:auto;
104 | }.navbar.fixed-left .navbar-nav .nav-item .dropdown-toggle:after{
105 | border-top:.3em solid transparent;
106 | border-left:.3em solid;
107 | border-bottom:.3em solid transparent;
108 | border-right:none;
109 | vertical-align:baseline
110 | }
111 | .navbar.fixed-left .navbar-nav .nav-item .dropdown-menu{
112 | left:100%
113 | }
114 | }
115 | $navbar-dark-active-color: rgb(255, 0, 55);
116 |
117 | .header{
118 | padding-left: 232px !important;
119 | }
120 |
121 | .createTestBtn {
122 | margin-right: 10px !important;
123 | }
124 | .carousel {
125 | width:500px;
126 | height:500px;
127 | margin: auto;
128 | }
129 |
130 |
131 |
132 | .content {
133 | padding-top: 100px;
134 | }
135 | @import "../../node_modules/bootstrap/scss/bootstrap";
136 | @import "../../node_modules/bootstrap/scss/functions";
137 | @import "../../node_modules/bootstrap/scss/variables";
138 | @import "../../node_modules/bootstrap/scss/mixins";
--------------------------------------------------------------------------------
/token:
--------------------------------------------------------------------------------
1 | eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbmM0djYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNlZTdmN2YyLTRkMDUtNGMwZi04NDUwLWM0ODE2YzEyMDdkMSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.FKgY9GcvPg_hs2dAPgSa1j983ZCaX_oaxNYCanPPu2BiyBx21V9BlsJZOdL_BUSedpFaCtaEtcnU8OQLzRy0_3oo6iDSauRU9hz-CRGFbiK4mWS9RRTFcjt88H8oQcZRXVsAwP8vylWJfA41_ADc1-R7Bgwef_dyiLaFRSyaYlyOQ6onl9fOXy346xrjrZY9AVSWtfkkg7GAjZDgSe1dQoaedfYTN-QyuvxXqWrx4NL0vokBSDOSePuI4GQpepmUzlEdi4BiuNrAqtL8gEVoEmYrCsw8RIxxPKIhE90I2aa7aGN42XD2YQ8vpzN7hvJPYuZR3rGJlAfhjWLVQozNXw#
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react",
5 | "module": "commonjs",
6 | "noImplicitAny": true,
7 | "outDir": "./build/",
8 | "preserveConstEnums": true,
9 | "removeComments": true,
10 | "sourceMap": true,
11 | "target": "es5"
12 | },
13 | "include": [
14 | "./src/**/*"
15 | ]
16 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin");
4 |
5 | module.exports = {
6 | entry: './src/index.tsx',
7 | output: {
8 | path: path.resolve(__dirname, 'build'),
9 | publicPath: '/',
10 | filename: 'bundle.js',
11 | },
12 | mode: 'development',
13 | devServer: {
14 | // Required for Docker to work with dev server
15 | // host: '0.0.0.0',
16 | host:'localhost',
17 | port: 8080,
18 | // match the output path
19 | contentBase: path.resolve(__dirname, 'build'),
20 | //enable HMR on the devServer
21 | hot: true,
22 | //match the output 'publicPath'
23 | publicPath: '/',
24 | // fallback to root for other urls
25 | historyApiFallback: true,
26 | inline: true,
27 | headers: { 'Access-Control-Allow-Origin': '*' },
28 |
29 | // proxy is required in order to make api calls to express server while using hot-reload webpack server
30 | // routes api fetch requests from localhost:8080/api/* (webpack dev server) to localhost:3000/api/* (where our Express server is running)
31 | proxy: {
32 | '/testing-ab': {
33 | target: 'http://localhost:3000/',
34 | secure: false,
35 | },
36 | '/data': {
37 | target: 'http://localhost:3000/',
38 | secure: false,
39 | },
40 | },
41 | },
42 | module: {
43 | rules: [
44 | {
45 | test: /\.tsx?$/,
46 | exclude: /node_modules/,
47 | use:
48 | {
49 | loader: "ts-loader",
50 | }
51 | },
52 | {
53 | enforce: "pre",
54 | test: /\.js$/,
55 | use:
56 | {
57 | loader: "source-map-loader"
58 | }
59 | },
60 | {
61 | test: /\.scss$/,
62 | use: [
63 | MiniCssExtractPlugin.loader,
64 | { loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
65 | { loader: 'sass-loader', options: { sourceMap: true } },
66 | ],
67 | },
68 | {
69 | test: /\.css$/,
70 | use: ['style-loader', 'css-loader']
71 | }
72 | ]
73 | },
74 | plugins: [
75 | new HtmlWebpackPlugin({
76 | template: "./index.html"
77 | }),
78 | new MiniCssExtractPlugin({
79 | // Options similar to the same options in webpackOptions.output
80 | // both options are optional
81 | filename: '[name].css',
82 | chunkFilename: '[id].css',
83 | })
84 | ],
85 | devtool: "source-map",
86 | resolve: {
87 | extensions: [".js", ".ts", ".tsx"]
88 | }
89 | }
--------------------------------------------------------------------------------