├── doc └── images │ ├── odo-conf-01.png │ ├── odo-conf-02.png │ ├── odo-conf-03.png │ ├── odo-conf-04.png │ ├── odo-conf-05.png │ ├── odo-jira-01.png │ ├── odo-jira-02.png │ ├── odo-jira-03.png │ ├── odo-jira-04.png │ ├── odo-jira-05.png │ ├── odo-ldap-01.png │ ├── odo-ldap-02.png │ ├── odo-ldap-03.png │ ├── odo-gitlab-01.png │ ├── odo-gitlab-02.png │ ├── odo-gitlab-03.png │ ├── odo-gitlab-04.png │ ├── odo-gitlab-05.png │ ├── odo-gitlab-06.png │ ├── odo-gitlab-07.png │ ├── odo-jenkins-01.png │ ├── odo-jenkins-02.png │ ├── odo-jenkins-03.png │ ├── odo-jenkins-04.png │ ├── odo-jenkins-05.png │ ├── odo-jenkins-06.png │ ├── odo-portal-01.png │ ├── odo-portal-02.png │ ├── odo-sonar-01.png │ ├── odo-sonar-02.png │ ├── odo-sonar-03.png │ ├── odo-framework-01.png │ └── odo-framework-02.png ├── odo-portal └── dockerBuild │ ├── images │ ├── harbor.png │ ├── jumpserver.png │ ├── password.png │ ├── ssp_help_1.png │ ├── ssp_help_2.png │ ├── ssp_help_3.png │ ├── gitlab.svg │ ├── rancher.svg │ ├── jira.svg │ ├── confluence.svg │ ├── sonar.svg │ └── jenkins.svg │ ├── Dockerfile │ ├── run.sh │ ├── ssp.html │ ├── index.html │ └── js │ └── bootstrap.min.js ├── .gitignore ├── odo-harbor └── dockerBuild │ └── Dockerfile ├── odo-mysql └── docker.cnf ├── odo-ldap ├── odo_users.ldif └── ssp │ └── config.inc.php ├── migrate_docker_images.sh ├── docker-compose.yaml ├── README.md ├── odo-sonar └── sonar.properties └── odoctl /doc/images/odo-conf-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-conf-01.png -------------------------------------------------------------------------------- /doc/images/odo-conf-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-conf-02.png -------------------------------------------------------------------------------- /doc/images/odo-conf-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-conf-03.png -------------------------------------------------------------------------------- /doc/images/odo-conf-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-conf-04.png -------------------------------------------------------------------------------- /doc/images/odo-conf-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-conf-05.png -------------------------------------------------------------------------------- /doc/images/odo-jira-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jira-01.png -------------------------------------------------------------------------------- /doc/images/odo-jira-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jira-02.png -------------------------------------------------------------------------------- /doc/images/odo-jira-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jira-03.png -------------------------------------------------------------------------------- /doc/images/odo-jira-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jira-04.png -------------------------------------------------------------------------------- /doc/images/odo-jira-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jira-05.png -------------------------------------------------------------------------------- /doc/images/odo-ldap-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-ldap-01.png -------------------------------------------------------------------------------- /doc/images/odo-ldap-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-ldap-02.png -------------------------------------------------------------------------------- /doc/images/odo-ldap-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-ldap-03.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-01.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-02.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-03.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-04.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-05.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-06.png -------------------------------------------------------------------------------- /doc/images/odo-gitlab-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-gitlab-07.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-01.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-02.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-03.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-04.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-05.png -------------------------------------------------------------------------------- /doc/images/odo-jenkins-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-jenkins-06.png -------------------------------------------------------------------------------- /doc/images/odo-portal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-portal-01.png -------------------------------------------------------------------------------- /doc/images/odo-portal-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-portal-02.png -------------------------------------------------------------------------------- /doc/images/odo-sonar-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-sonar-01.png -------------------------------------------------------------------------------- /doc/images/odo-sonar-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-sonar-02.png -------------------------------------------------------------------------------- /doc/images/odo-sonar-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-sonar-03.png -------------------------------------------------------------------------------- /doc/images/odo-framework-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-framework-01.png -------------------------------------------------------------------------------- /doc/images/odo-framework-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/doc/images/odo-framework-02.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/harbor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/harbor.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/jumpserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/jumpserver.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/password.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/ssp_help_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/ssp_help_1.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/ssp_help_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/ssp_help_2.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/ssp_help_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QualitySphere/OpenDevOps/HEAD/odo-portal/dockerBuild/images/ssp_help_3.png -------------------------------------------------------------------------------- /odo-portal/dockerBuild/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.16-alpine 2 | LABEL maintainer="v.stone@163.com" 3 | RUN cd /usr/share/nginx && \ 4 | rm -rf html && \ 5 | mkdir html 6 | WORKDIR /usr/share/nginx/html 7 | COPY . . 8 | CMD ["sh", "run.sh"] 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | odo-ldap/db/ 3 | odo-ldap/config/ 4 | odo-mysql/mysql/ 5 | odo-pg/ 6 | odo-jira/ 7 | odo-conf/ 8 | odo-gitlab/ 9 | odo-jenkins/ 10 | odo-sonar/data/ 11 | odo-sonar/logs/ 12 | odo-sonar/extensions/ 13 | odo-jms/ 14 | odo-rancher/ 15 | odo-harbor/ 16 | -------------------------------------------------------------------------------- /odo-harbor/dockerBuild/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM busybox 2 | RUN mkdir /harbor_installer && \ 3 | mkdir /workspace && \ 4 | cd /harbor_installer && \ 5 | wget https://github.com/goharbor/harbor/releases/download/v2.1.0/harbor-offline-installer-v2.1.0.tgz -O harbor.tgz && \ 6 | tar zvxf harbor.tgz && \ 7 | rm -rf harbor.tgz 8 | CMD mv /harbor_installer/harbor/* /workspace/ 9 | -------------------------------------------------------------------------------- /odo-mysql/docker.cnf: -------------------------------------------------------------------------------- 1 | [client] 2 | default-character-set = utf8mb4 3 | [mysqld] 4 | default-storage-engine=INNODB 5 | character_set_server=utf8mb4 6 | innodb_default_row_format=DYNAMIC 7 | innodb_large_prefix=ON 8 | innodb_file_format=Barracuda 9 | innodb_log_file_size=2G 10 | sql_mode=ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 11 | 12 | transaction-isolation=READ-COMMITTED 13 | binlog_format=row 14 | max_allowed_packet = 56M 15 | 16 | innodb_buffer_pool_size = 1024M 17 | innodb_log_file_size = 256M 18 | query_cache_size = 16M 19 | query_cache_type = 1 20 | max_connections = 200 21 | skip_ssl 22 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/gitlab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | update_index_html() 5 | { 6 | element_id=${1?} 7 | element_url=${2?} 8 | if [ "${element_url}" != "" ]; then 9 | sed -i "s#id='${element_id}'.*#id='${element_id}' onclick='window.open(\"${element_url}\")'#g" index.html 10 | fi 11 | return 0 12 | } 13 | 14 | update_ssp_html() 15 | { 16 | element_id=${1?} 17 | element_href=${2?} 18 | if [ "${element_href}" != "" ]; then 19 | sed -i "s#id='${element_id}'.*#id='${element_id}' href='${element_href}' target='_blank'#g" ssp.html 20 | fi 21 | return 0 22 | } 23 | 24 | # Main 25 | ## Update index.html 26 | for _URL in $(env | grep ODO_) 27 | do 28 | _KEY=$(echo "${_URL}" | awk -F '=' '{print $1}') 29 | _VALUE=$(echo "${_URL}" | awk -F '=' '{print $2}') 30 | update_index_html "${_KEY}" "${_VALUE}" 31 | done 32 | 33 | ## Update ssp.html 34 | if [ -z "${ODO_SSP_URL}" ]; then 35 | update_ssp_html ODO_SSP_URL_1 "${ODO_SSP_URL}" 36 | update_ssp_html ODO_SSP_URL_2 "${ODO_SSP_URL}" 37 | fi 38 | 39 | ## Start Nginx 40 | nginx -g "daemon off;" 41 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/rancher.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 12 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /odo-ldap/odo_users.ldif: -------------------------------------------------------------------------------- 1 | # Obsolete, OrgUnit 2 | dn: ou=obsolete,dc=qualitysphere,dc=github,dc=io 3 | ou: obsolete 4 | objectClass: organizationalUnit 5 | 6 | # Users, OrgUnit 7 | dn: ou=users,dc=qualitysphere,dc=github,dc=io 8 | ou: users 9 | objectClass: organizationalUnit 10 | 11 | # ODO, User 12 | dn: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 13 | cn: odo 14 | uid: odo 15 | sn: odo 16 | displayName: Open DevOps 17 | mail: odo@QualitySphere.github.io 18 | userPassword: opendevops 19 | objectClass: inetOrgPerson 20 | 21 | # Groups, OrgUnit 22 | dn: ou=groups,dc=qualitysphere,dc=github,dc=io 23 | ou: groups 24 | objectClass: organizationalUnit 25 | 26 | # jira-administrators, Group 27 | dn: cn=jira-administrators,ou=groups,dc=qualitysphere,dc=github,dc=io 28 | cn: jira-administrators 29 | uniqueMember: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 30 | objectClass: groupOfUniqueNames 31 | 32 | # jira-software-users, Group 33 | dn: cn=jira-software-users,ou=groups,dc=qualitysphere,dc=github,dc=io 34 | cn: jira-software-users 35 | uniqueMember: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 36 | objectClass: groupOfUniqueNames 37 | 38 | # jira-servicedesk-users, Group 39 | dn: cn=jira-servicedesk-users,ou=groups,dc=qualitysphere,dc=github,dc=io 40 | cn: jira-servicedesk-users 41 | uniqueMember: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 42 | objectClass: groupOfUniqueNames 43 | 44 | # confluence-administrators, Group 45 | dn: cn=confluence-administrators,ou=groups,dc=qualitysphere,dc=github,dc=io 46 | cn: confluence-administrators 47 | uniqueMember: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 48 | objectClass: groupOfUniqueNames 49 | 50 | # confluence-users, Group 51 | dn: cn=confluence-users,ou=groups,dc=qualitysphere,dc=github,dc=io 52 | cn: confluence-users 53 | uniqueMember: cn=odo,ou=users,dc=qualitysphere,dc=github,dc=io 54 | objectClass: groupOfUniqueNames 55 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/ssp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Self Service Password Help 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Open DevOps 账号说明

18 |

每位成员都会拥有唯一的用户名和对应的邮箱,通常情况下用户名和邮箱名同名,如用户名 odo 邮箱为 odo@QualitySphere.github.io

19 |

初始密码为 opendevops

20 |

强烈建议拿到账号之后第一时间修改密码

21 |

通过页面修改密码

22 |

访问 Self Service Password

25 |

根据页面提示输入旧密码自助修改新密码

26 |

示例如下:

27 | 28 |

通过邮箱重置密码

29 |

访问 Self Service Password

32 |

点击页面上 通过邮件发送密码重置链接 的链接,根据页面提示输入匹配的用户名和邮箱

33 |

提交后等待邮箱收到密码重置邮件

34 |

示例如下:

35 | 36 |

37 | 38 |

39 |
40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /migrate_docker_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -ex 3 | # ssp, jira-software, confluence-server NO NEED to migrate 4 | 5 | registry="registry.cn-hangzhou.aliyuncs.com" 6 | repo="bxwill" 7 | 8 | source_img="dinkel/openldap:latest" 9 | target_img="${registry}/${repo}/openldap:latest" 10 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 11 | 12 | source_img="dinkel/phpldapadmin:latest" 13 | target_img="${registry}/${repo}/phpldapadmin:latest" 14 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 15 | 16 | #source_img="mysql:5.7" 17 | #target_img="${registry}/${repo}/mysql:5.7" 18 | #docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 19 | 20 | source_img="postgres:10" 21 | target_img="${registry}/${repo}/postgres:10" 22 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 23 | 24 | source_img="gitlab/gitlab-ce:13.3.5-ce.0" 25 | target_img="${registry}/${repo}/gitlab-ce:13.3.5" 26 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 27 | 28 | source_img="jenkinsci/blueocean" 29 | target_img="${registry}/${repo}/jenkins:blueocean" 30 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 31 | 32 | source_img="sonarqube:7.9-community" 33 | target_img="${registry}/${repo}/sonar:7.9" 34 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 35 | 36 | source_img="rancher/rancher:v2.4.8" 37 | target_img="${registry}/${repo}/rancher:2.4.8" 38 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 39 | 40 | source_img="jumpserver/jms_all:v2.1.2" 41 | target_img="${registry}/${repo}/jms_all:2.1.2" 42 | docker pull ${source_img} && docker tag ${source_img} ${target_img} && docker push ${target_img} 43 | 44 | target_img="${registry}/${repo}/odo-portal:latest" 45 | cd odo-portal/dockerBuild && docker build -t ${target_img} . && docker push ${target_img} 46 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/jira.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | Jira Software-blue 27 | 28 | 29 | 30 | 51 | 53 | 55 | 62 | 66 | 70 | 71 | 78 | 79 | Jira Software-blue 81 | 84 | 86 | 90 | 94 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/confluence.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | Confluence-blue 27 | 28 | 29 | 30 | 50 | 52 | 54 | 61 | 65 | 69 | 70 | 78 | 79 | Confluence-blue 81 | 84 | 86 | 90 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/images/sonar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | odo-ldap-openldap: 5 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/openldap 6 | container_name: odo-ldap-openldap 7 | restart: always 8 | deploy: 9 | resources: 10 | limits: 11 | cpus: '0.5' 12 | memory: '1G' 13 | ports: 14 | - 18389:389 15 | volumes: 16 | - ./odo-ldap/db:/var/lib/ldap 17 | - ./odo-ldap/config:/etc/ldap 18 | environment: 19 | SLAPD_DOMAIN: qualitysphere.github.io 20 | SLAPD_PASSWORD: opendevops 21 | 22 | odo-ldap-phpldapadmin: 23 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/phpldapadmin 24 | container_name: odo-ldap-phpldapadmin 25 | restart: always 26 | deploy: 27 | resources: 28 | limits: 29 | cpus: '0.5' 30 | memory: '512M' 31 | ports: 32 | - 18880:80 33 | environment: 34 | LDAP_SERVER_HOST: odo-ldap-openldap 35 | 36 | odo-ldap-ssp: 37 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/ssp:1.3 38 | container_name: odo-ldap-ssp 39 | restart: always 40 | deploy: 41 | resources: 42 | limits: 43 | cpus: '0.5' 44 | memory: '512M' 45 | ports: 46 | - 18080:80 47 | volumes: 48 | - ./odo-ldap/ssp/config.inc.php:/var/www/html/conf/config.inc.php 49 | 50 | odo-pg: 51 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/postgres:10 52 | container_name: odo-pg 53 | restart: always 54 | deploy: 55 | resources: 56 | limits: 57 | cpus: '2' 58 | memory: '4G' 59 | ports: 60 | - 18432:5432 61 | volumes: 62 | - ./odo-pg:/var/lib/postgresql/data 63 | environment: 64 | POSTGRES_USER: postgres 65 | POSTGRES_PASSWORD: opendevops 66 | 67 | odo-jira: 68 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/jira-software:8.11 69 | container_name: odo-jira 70 | restart: always 71 | deploy: 72 | resources: 73 | limits: 74 | cpus: '2' 75 | memory: '8G' 76 | ports: 77 | - 8080:8080 78 | volumes: 79 | - ./odo-jira:/var/atlassian/application-data/jira 80 | 81 | odo-conf: 82 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/confluence-server:7.5 83 | container_name: odo-conf 84 | restart: always 85 | deploy: 86 | resources: 87 | limits: 88 | cpus: '2' 89 | memory: '8G' 90 | ports: 91 | - 8090:8090 92 | - 8091:8091 93 | volumes: 94 | - ./odo-conf:/var/atlassian/application-data/confluence 95 | 96 | odo-gitlab: 97 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/gitlab-ce:13.3.5 98 | container_name: odo-gitlab 99 | restart: always 100 | deploy: 101 | resources: 102 | limits: 103 | cpus: '2' 104 | memory: '8G' 105 | ports: 106 | - 12080:80 107 | - 12443:443 108 | - 222:222 109 | volumes: 110 | - ./odo-gitlab/data:/var/opt/gitlab 111 | - ./odo-gitlab/config:/etc/gitlab 112 | 113 | odo-jenkins: 114 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/jenkins:blueocean 115 | container_name: odo-jenkins 116 | restart: always 117 | deploy: 118 | resources: 119 | limits: 120 | cpus: '2' 121 | memory: '8G' 122 | ports: 123 | - 15080:8080 124 | - 50000:50000 125 | volumes: 126 | - ./odo-jenkins/jenkins_home:/var/jenkins_home 127 | - /var/run/docker.sock:/var/run/docker.sock 128 | 129 | odo-sonar: 130 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/sonar:7.9 131 | container_name: odo-sonar 132 | restart: always 133 | deploy: 134 | resources: 135 | limits: 136 | cpus: '2' 137 | memory: '4G' 138 | ports: 139 | - 9000:9000 140 | environment: 141 | SONARQUBE_JDBC_URL: "jdbc:postgresql://odo-pg:5432/sonar" 142 | SONARQUBE_JDBC_USERNAME: postgres 143 | SONARQUBE_JDBC_PASSWORD: opendevops 144 | volumes: 145 | - ./odo-sonar/data:/opt/sonarqube/data 146 | - ./odo-sonar/logs:/opt/sonarqube/logs 147 | - ./odo-sonar/extensions:/opt/sonarqube/extensions 148 | - ./odo-sonar/sonar.properties:/opt/sonarqube/conf/sonar.properties 149 | 150 | odo-harbor: 151 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/harbor:installer-2.1.0 152 | container_name: odo-harbor 153 | deploy: 154 | resources: 155 | limits: 156 | cpus: '0.1' 157 | memory: '512M' 158 | volumes: 159 | - ./odo-harbor/:/workspace/ 160 | 161 | odo-rancher: 162 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/rancher:2.4.8 163 | container_name: odo-rancher 164 | restart: always 165 | deploy: 166 | resources: 167 | limits: 168 | cpus: '2' 169 | memory: '8G' 170 | ports: 171 | - 17443:443 172 | volumes: 173 | - ./odo-rancher:/var/lib/rancher 174 | environment: 175 | CATTLE_SYSTEM_CATALOG: bundled 176 | AUDIT_LEVEL: 3 177 | 178 | odo-jms: 179 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/jms_all:2.1.2 180 | container_name: odo-jms 181 | restart: always 182 | deploy: 183 | resources: 184 | limits: 185 | cpus: '2' 186 | memory: '8G' 187 | ports: 188 | - 17080:80 189 | - 2222:2222 190 | volumes: 191 | - ./odo-jms/data:/opt/jumpserver/data 192 | - ./odo-jms/mysql:/var/lib/mysql 193 | environment: 194 | SECRET_KEY: UGFn28Pp09SiJr60OMXs8e7lAqhJa3O1ztK8tJhMB5Aq1XNF6g 195 | BOOTSTRAP_TOKEN: KIaSh2O7JR8r6Q0m 196 | 197 | odo-portal: 198 | image: registry.cn-hangzhou.aliyuncs.com/bxwill/odo-portal 199 | container_name: odo-portal 200 | restart: always 201 | deploy: 202 | resources: 203 | limits: 204 | cpus: '0.2' 205 | memory: '512M' 206 | ports: 207 | - 80:80 208 | - 443:443 209 | # environment: 210 | # ODO_PHPLDAPADMIN_URL: http://localhost:18880 211 | # ODO_JIRA_URL: http://localhost:8080 212 | # ODO_CONF_URL: http://localhost:8090 213 | # ODO_SSP_URL: http://localhost:18080 214 | # ODO_GITLAB_URL: http://localhost:12080 215 | # ODO_HARBOR_URL: http://localhost:16080 216 | # ODO_SONAR_URL: http://localhost:9000 217 | # ODO_JENKINS_URL: http://localhost:15080 218 | # ODO_JMS_URL: http://localhost:17080 219 | # ODO_RANCHER_URL: https://localhost:17443 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenDevOps 2 | ###### This is ONLY for DevOps learning and practice. Please contact the software vendor to get the product license if you are a company. 3 | 4 | > **Table of Contents** 5 | > - Framework 6 | > - Quick Start 7 | > - Resource 8 | > - Deployment 9 | > - Configuration 10 | > - OpenLDAP 11 | > - Self Service Password 12 | > - Jira Software 13 | > - Confluence 14 | > - GitLab 15 | > - SonarQube 16 | > - Jenkins 17 | > - Harbor 18 | > - Rancher 19 | > - JumpServer 20 | > - Manual 21 | > - Tool Chain 22 | > - odoctl 23 | > - ODO Dockerfiles 24 | 25 | ## Framework 26 | 27 | ![Open DevOps Services](doc/images/odo-framework-01.png) 28 | ![ODO Framework](doc/images/odo-framework-02.png) 29 | 30 | ## Quick Start 31 | 32 | #### Resource 33 | 34 | Type | CPU | Memory 35 | ----|----|---- 36 | Minimum | 4 core | 8 G 37 | Recommended | 8 core | 16 G 38 | Optimum | 16 core | 32 G 39 | 40 | #### Deployment 41 | 42 | 1. Clone project
`git clone https://github.com/QualitySphere/OpenDevOps.git` 43 | 2. Change dir to ODO home
`cd OpenDevOps` 44 | 3. Enable and update `odo-portal` environment part in `docker-compose.yaml`
Change localhost to your server IP or domain
![ODO Portal YAML](doc/images/odo-portal-01.png) 45 | 4. Start ODO services
`./odoctl start all` 46 | 5. Access ODO-Portal `http://ODO-HOST`
![ODO Portal](doc/images/odo-portal-02.png) 47 | 48 | #### Configuration 49 | 50 | - **OpenLDAP** 51 | - Auto-init 52 | - **Self** **Service** **Password** 53 | - Access Self Service Password `http://ODO-HOST:18080` 54 | - Try to update default account `odo`'s password to validate SSP 55 | - Try to update `odo`'s password via E-mail.
if you find there is no hostname in the reset password link, you can update `$reset_url` in `odo-ldap/ssp/config.inc.php` 56 | - **Jira** **Software** 57 | - Auto-init 58 | - **Confluence** 59 | - Auto-init 60 | - **GitLab** 61 | - Auto-init 62 | - **SonarQube** 63 | - Auto-init 64 | - **Jenkins** 65 | - Access Jenkins `http://ODO-HOST:15080` to unlock it 66 | - You can get `initialAdminPassword` via otoctl tool `./odoctl license jenkins` in ODO-HOST
![](doc/images/odo-jenkins-01.png) 67 | - ![](doc/images/odo-jenkins-02.png) 68 | - Add/Remove the plugins to config Jenkins
![](doc/images/odo-jenkins-03.png) 69 | - check `GitLab` `Publish Over SSH` `SSH` 70 | - uncheck `Ant` `Gradle` 71 | - Waiting for installation complete
![](doc/images/odo-jenkins-04.png) 72 | - Use default admin account to continue
![](doc/images/odo-jenkins-05.png) 73 | - Try to config LDAP later
![](doc/images/odo-jenkins-06.png) 74 | - **Harbor** 75 | - To Be Written 76 | - **Rancher** 77 | - To Be Written 78 | - **JumpServer** 79 | - To Be Written 80 | 81 | #### Manual 82 | 83 | - [Jira Software](https://docs.atlassian.com/jira/jsw-docs-0811/) 84 | - [Confluence](https://docs.atlassian.com/confluence/docs-75/) 85 | - [GitLab](https://docs.gitlab.com/ee/README.html) 86 | - [SonarQube](https://docs.sonarqube.org/latest/) 87 | - [Jenkins](https://www.jenkins.io/zh/doc/book/blueocean/creating-pipelines/) 88 | - [Harbor](https://goharbor.io/docs/2.0.0/working-with-projects/) 89 | - [Rancher](https://rancher.com/docs/rancher/v2.x/en/) 90 | - [JumpServer](https://docs.jumpserver.org/zh/master/admin-guide/quick_start/) 91 | 92 | ## Tool Chain 93 | 94 | Service|Port|Container Port|Volume|Container Volume 95 | ----|----|----|----|---- 96 | OpenLDAP|18389|389|odo-ldap/db
odo-ldap/config|/var/lig/ldap
/etc/ldap 97 | PHPLdapAdmin|18880|80|-|- 98 | Self Service Password|18080|80|odo-ldap/ssp/config.inc.php|/var/www/html/conf/config.inc.php 99 | PostgresQL|18432|5432|odo-pg|/var/lib/postgresql/data 100 | Jira|8080|8080|odo-jira|/var/atlassian/application-data/jira 101 | Confluence|8090
8091|8090
8091|odo-conf|/var/atlassian/application-data/confluence 102 | GitLab|12080
12443
222|80
443
222|odo-gitlab/data
odo-gitlab/config|/var/opt/gitlab
/etc/gitlab 103 | Jenkins|15080
50000|8080
50000|odo-jenkins/jenkins_home
/var/run/docker.sock|/var/jenkins_home
/var/run/docker.sock 104 | SonarQube|9000|9000|odo-sonar/data
odo-sonar/logs
odo-sonar/extensions
odo-sonar/sonar.properties|/opt/sonarqube/data
/opt/sonarqube/logs
/opt/sonarqube/extensions
/opt/sonarqube/conf/sonar.properties 105 | Harbor|16080|80|odo-harbor| 106 | Rancher|17443|443|odo-rancher|/var/lib/rancher 107 | JumpServer|17080
2222|80
2222|odo-jms/data
odo-jms/mysql|/opt/jumpserver/data
/var/lib/mysql 108 | Portal|80
443|80
443|| 109 | 110 | ## odoctl 111 | 112 | - commands 113 | ```bash 114 | ./odoctl : 115 | start - Up container(s) to start service(s) and init them 116 | start_no_init - Up container(s) to start service(s) 117 | stop - Stop container(s) to stop service(s) 118 | down - Down all services 119 | restart - Restart container(s) to restart service(s) 120 | list - List container(s) 121 | license - Generate JIRA/Confluence/Plugin license 122 | cleanup - Cleanup all containers and dirs 123 | ``` 124 | 125 | - services 126 | ```bash 127 | ./odoctl start/stop/restart : 128 | all - All Services 129 | ldap - OpenLDAP, PhpLDAPAdmin and Self Service Password 130 | pg - PostgresQL 131 | jira - Jira Software 132 | conf - Confluence 133 | sonar - SonarQube Community Edition 134 | jenkins - Jenkins 135 | gitlab - GitLab Community Edition 136 | rancher - Rancher 137 | jms - JumpServer 138 | portal - DevOps Portal 139 | ``` 140 | 141 | - list containers 142 | ```bash 143 | ./odoctl list 144 | ``` 145 | 146 | - generate license for JIRA/Confluence 147 | ```bash 148 | ./odoctl license : 149 | jira - Generate JIRA software license 150 | jira_plugin - Generate JIRA plugin license 151 | conf - Generate Confluence server license 152 | conf_plugin - Generate Confluence plugin license 153 | jenkins - Get Jenkins initialAdminPassword 154 | 155 | ./odoctl license jira_plugin/conf/conf_plugin : 156 | PRODUCT_ID is REQUIRED 157 | +-------------+------------+------------------------------------+ 158 | | PRODUCT | PRODUCT_ID | WHERE | 159 | +-------------+------------+------------------------------------+ 160 | | jira_plugin | plugin ID | JIRA application detail page | 161 | +-------------+------------+------------------------------------+ 162 | | conf | server ID | Confluence installation page | 163 | +-------------+------------+------------------------------------+ 164 | | conf_plugin | plugin ID | Confluence application detail page | 165 | +-------------+------------+------------------------------------+ 166 | ``` 167 | 168 | - cleanup ODO services and dirs 169 | 170 | ```bash 171 | ./odoctl cleanup 172 | ``` 173 | 174 | ## ODO Dockerfiles 175 | 176 | - [Self Service Password](https://github.com/seoktaehyeon/docker-self-service-password/blob/1.3/Dockerfile) 177 | - [Jira Software](https://github.com/seoktaehyeon/docker-jira-software/blob/8.11/Dockerfile) 178 | - [Confluence Server](https://github.com/seoktaehyeon/docker-confluence-server/blob/7.5/Dockerfile) 179 | - [ODO Portal](odo-portal/dockerBuild/Dockerfile) 180 | - [ODO Harbor Installer](odo-harbor/dockerBuild/Dockerfile) 181 | 182 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Open DevOps Services 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
71 | 72 |
73 |

Jira Software

74 |

项目与事务跟踪工具,被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域。

75 |
76 |
77 |
78 |
79 |
82 | 83 |
84 |

Confluence

85 |

企业知识管理与协同软件,使用简单,但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论,信息推送。

86 |
87 |
88 |
89 |
90 |
93 | 94 |
95 |

Self Service Password

96 |

自助修改密码服务,是一款 PHP 应用程序,允许用户在 LDAP 目录中更改密码,若忘记密码,还可通过邮件进行密码重置。

97 |
98 |
99 |
100 |
101 |
102 |
103 |
106 | 107 |
108 |

GitLab

109 |

使用 Git 作为代码管理工具,并在此基础上搭建起来的 web 服务。

110 |
111 |
112 |
113 |
114 |
117 | 118 |
119 |

Harbor

120 |

尚未集成 LDAP

121 |

一个开源镜像管理工具,提供了兼容性、性能和互操作性,帮助用户在像 Kubernetes 和 Docker 122 | 这样的云本地计算平台上稳定安全地管理镜像。

123 |
124 |
125 |
126 |
127 |
130 | 131 |
132 |

SonarQube

133 |

用于管理代码质量的开放平台,可快速定位代码中潜在的或明显的错误。目前支持 java, C#, C/C++, Python, PL/SQL, Cobol, JavaScript, 134 | Groovy 等二十几种编程语言的代码质量管理与检测。

135 |
136 |
137 |
138 |
139 |
140 |
141 |
144 | 145 |
146 |

Jenkins

147 |

基于 Java 开发的一种持续集成工具,用于监控持续重复的工作,使软件的持续集成变成可能。

148 |
149 |
150 |
151 |
152 |
155 | 156 |
157 |

JumpServer

158 |

开源的堡垒机, 使用 GNU GPL v2.0 开源协议, 是符合 4A 的专业运维审计系统。配备 Web Terminal 解决方案, 交互界面美观、用户体验好,支持管理 159 | SSH、 Telnet、 RDP、 VNC 协议资产。

160 |
161 |
162 |
163 |
164 |
167 | 168 |
169 |

Rancher

170 |

容器管理平台,通过 Rancher 可以实现 Docker 和 Kubernetes 的轻松部署。

171 |
172 |
173 |
174 |
175 |
176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /odo-ldap/ssp/config.inc.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /odo-sonar/sonar.properties: -------------------------------------------------------------------------------- 1 | # Property values can: 2 | # - reference an environment variable, for example sonar.jdbc.url= ${env:SONAR_JDBC_URL} 3 | # - be encrypted. See https://redirect.sonarsource.com/doc/settings-encryption.html 4 | 5 | #-------------------------------------------------------------------------------------------------- 6 | # DATABASE 7 | # 8 | # IMPORTANT: 9 | # - The embedded H2 database is used by default. It is recommended for tests but not for 10 | # production use. Supported databases are Oracle, PostgreSQL and Microsoft SQLServer. 11 | # - Changes to database connection URL (sonar.jdbc.url) can affect SonarSource licensed products. 12 | 13 | # User credentials. 14 | # Permissions to create tables, indices and triggers must be granted to JDBC user. 15 | # The schema must be created first. 16 | #sonar.jdbc.username= 17 | #sonar.jdbc.password= 18 | 19 | #----- Embedded Database (default) 20 | # H2 embedded database server listening port, defaults to 9092 21 | #sonar.embeddedDatabase.port=9092 22 | 23 | 24 | #----- Oracle 11g/12c/18c/19c 25 | # The Oracle JDBC driver must be copied into the directory extensions/jdbc-driver/oracle/. 26 | # Only the thin client is supported, and we recommend using the latest Oracle JDBC driver. See 27 | # https://jira.sonarsource.com/browse/SONAR-9758 for more details. 28 | # If you need to set the schema, please refer to http://jira.sonarsource.com/browse/SONAR-5000 29 | #sonar.jdbc.url=jdbc:oracle:thin:@localhost:1521/XE 30 | 31 | 32 | #----- PostgreSQL 9.3 or greater 33 | # By default the schema named "public" is used. It can be overridden with the parameter "currentSchema". 34 | #sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube?currentSchema=my_schema 35 | 36 | 37 | #----- Microsoft SQLServer 2014/2016/2017 and SQL Azure 38 | # A database named sonar must exist and its collation must be case-sensitive (CS) and accent-sensitive (AS) 39 | # Use the following connection string if you want to use integrated security with Microsoft Sql Server 40 | # Do not set sonar.jdbc.username or sonar.jdbc.password property if you are using Integrated Security 41 | # For Integrated Security to work, you have to download the Microsoft SQL JDBC driver package from 42 | # https://www.microsoft.com/en-us/download/details.aspx?id=55539 43 | # and copy sqljdbc_auth.dll to your path. You have to copy the 32 bit or 64 bit version of the dll 44 | # depending upon the architecture of your server machine. 45 | #sonar.jdbc.url=jdbc:sqlserver://localhost;databaseName=sonar;integratedSecurity=true 46 | 47 | # Use the following connection string if you want to use SQL Auth while connecting to MS Sql Server. 48 | # Set the sonar.jdbc.username and sonar.jdbc.password appropriately. 49 | #sonar.jdbc.url=jdbc:sqlserver://localhost;databaseName=sonar 50 | 51 | 52 | #----- Connection pool settings 53 | # The maximum number of active connections that can be allocated 54 | # at the same time, or negative for no limit. 55 | # The recommended value is 1.2 * max sizes of HTTP pools. For example if HTTP ports are 56 | # enabled with default sizes (50, see property sonar.web.http.maxThreads) 57 | # then sonar.jdbc.maxActive should be 1.2 * 50 = 60. 58 | #sonar.jdbc.maxActive=60 59 | 60 | # The maximum number of connections that can remain idle in the 61 | # pool, without extra ones being released, or negative for no limit. 62 | #sonar.jdbc.maxIdle=5 63 | 64 | # The minimum number of connections that can remain idle in the pool, 65 | # without extra ones being created, or zero to create none. 66 | #sonar.jdbc.minIdle=2 67 | 68 | # The maximum number of milliseconds that the pool will wait (when there 69 | # are no available connections) for a connection to be returned before 70 | # throwing an exception, or <= 0 to wait indefinitely. 71 | #sonar.jdbc.maxWait=5000 72 | 73 | #sonar.jdbc.minEvictableIdleTimeMillis=600000 74 | #sonar.jdbc.timeBetweenEvictionRunsMillis=30000 75 | 76 | 77 | 78 | #-------------------------------------------------------------------------------------------------- 79 | # WEB SERVER 80 | # Web server is executed in a dedicated Java process. By default heap size is 512MB. 81 | # Use the following property to customize JVM options. 82 | # Recommendations: 83 | # 84 | # The HotSpot Server VM is recommended. The property -server should be added if server mode 85 | # is not enabled by default on your environment: 86 | # http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html 87 | # 88 | # Startup can be long if entropy source is short of entropy. Adding 89 | # -Djava.security.egd=file:/dev/./urandom is an option to resolve the problem. 90 | # See https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source 91 | # 92 | #sonar.web.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError 93 | 94 | # Same as previous property, but allows to not repeat all other settings like -Xmx 95 | #sonar.web.javaAdditionalOpts= 96 | 97 | # Binding IP address. For servers with more than one IP address, this property specifies which 98 | # address will be used for listening on the specified ports. 99 | # By default, ports will be used on all IP addresses associated with the server. 100 | #sonar.web.host=0.0.0.0 101 | 102 | # Web context. When set, it must start with forward slash (for example /sonarqube). 103 | # The default value is root context (empty value). 104 | #sonar.web.context= 105 | # TCP port for incoming HTTP connections. Default value is 9000. 106 | #sonar.web.port=9000 107 | 108 | 109 | # The maximum number of connections that the server will accept and process at any given time. 110 | # When this number has been reached, the server will not accept any more connections until 111 | # the number of connections falls below this value. The operating system may still accept connections 112 | # based on the sonar.web.connections.acceptCount property. The default value is 50. 113 | #sonar.web.http.maxThreads=50 114 | 115 | # The minimum number of threads always kept running. The default value is 5. 116 | #sonar.web.http.minThreads=5 117 | 118 | # The maximum queue length for incoming connection requests when all possible request processing 119 | # threads are in use. Any requests received when the queue is full will be refused. 120 | # The default value is 25. 121 | #sonar.web.http.acceptCount=25 122 | 123 | # By default users are logged out and sessions closed when server is restarted. 124 | # If you prefer keeping user sessions open, a secret should be defined. Value is 125 | # HS256 key encoded with base64. It must be unique for each installation of SonarQube. 126 | # Example of command-line: 127 | # echo -n "type_what_you_want" | openssl dgst -sha256 -hmac "key" -binary | base64 128 | #sonar.auth.jwtBase64Hs256Secret= 129 | 130 | # The inactivity timeout duration of user sessions, in minutes. After the configured 131 | # period of time, the user is logged out. 132 | # The default value is set to 3 days (4320 minutes) 133 | # and cannot be greater than 3 months. Value must be strictly positive. 134 | #sonar.web.sessionTimeoutInMinutes=4320 135 | 136 | # A passcode can be defined to access some web services from monitoring 137 | # tools without having to use the credentials of a system administrator. 138 | # Check the Web API documentation to know which web services are supporting this authentication mode. 139 | # The passcode should be provided in HTTP requests with the header "X-Sonar-Passcode". 140 | # By default feature is disabled. 141 | #sonar.web.systemPasscode= 142 | 143 | 144 | #-------------------------------------------------------------------------------------------------- 145 | # SSO AUTHENTICATION 146 | 147 | # Enable authentication using HTTP headers 148 | #sonar.web.sso.enable=false 149 | 150 | # Name of the header to get the user login. 151 | # Only alphanumeric, '.' and '@' characters are allowed 152 | #sonar.web.sso.loginHeader=X-Forwarded-Login 153 | 154 | # Name of the header to get the user name 155 | #sonar.web.sso.nameHeader=X-Forwarded-Name 156 | 157 | # Name of the header to get the user email (optional) 158 | #sonar.web.sso.emailHeader=X-Forwarded-Email 159 | 160 | # Name of the header to get the list of user groups, separated by comma (optional). 161 | # If the sonar.sso.groupsHeader is set, the user will belong to those groups if groups exist in SonarQube. 162 | # If none of the provided groups exists in SonarQube, the user will only belong to the default group. 163 | # Note that the default group will always be set. 164 | #sonar.web.sso.groupsHeader=X-Forwarded-Groups 165 | 166 | # Interval used to know when to refresh name, email and groups. 167 | # During this interval, if for instance the name of the user is changed in the header, it will only be updated after X minutes. 168 | #sonar.web.sso.refreshIntervalInMinutes=5 169 | 170 | #-------------------------------------------------------------------------------------------------- 171 | # LDAP CONFIGURATION 172 | 173 | # Enable the LDAP feature 174 | #sonar.security.realm=LDAP 175 | 176 | # Set to true when connecting to a LDAP server using a case-insensitive setup. 177 | # sonar.authenticator.downcase=true 178 | 179 | # URL of the LDAP server. Note that if you are using ldaps, then you should install the server certificate into the Java truststore. 180 | ldap.url=ldap://odo-ldap-openldap:389 181 | 182 | # Bind DN is the username of an LDAP user to connect (or bind) with. Leave this blank for anonymous access to the LDAP directory (optional) 183 | ldap.bindDn=cn=admin,dc=qualitysphere,dc=github,dc=io 184 | 185 | # Bind Password is the password of the user to connect with. Leave this blank for anonymous access to the LDAP directory (optional) 186 | ldap.bindPassword=opendevops 187 | 188 | # Possible values: simple | CRAM-MD5 | DIGEST-MD5 | GSSAPI See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html (default: simple) 189 | # ldap.authentication=simple 190 | 191 | # See : 192 | # * http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html 193 | # * http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html 194 | # (optional) 195 | # ldap.realm=example.org 196 | 197 | # Context factory class (optional) 198 | # ldap.contextFactoryClass=com.sun.jndi.ldap.LdapCtxFactory 199 | 200 | # Enable usage of StartTLS (default : false) 201 | # ldap.StartTLS=true 202 | 203 | # Follow or not referrals. See http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html (default: true) 204 | # ldap.followReferrals=false 205 | 206 | # USER MAPPING 207 | 208 | # Distinguished Name (DN) of the root node in LDAP from which to search for users (mandatory) 209 | ldap.user.baseDn=ou=users,dc=qualitysphere,dc=github,dc=io 210 | 211 | # LDAP user request. (default: (&(objectClass=inetOrgPerson)(uid={login})) ) 212 | # ldap.user.request=(&(objectClass=user)(sAMAccountName={login})) 213 | ldap.user.request=(&(objectClass=inetOrgPerson)(cn={login})) 214 | 215 | # Attribute in LDAP defining the user’s real name. (default: cn) 216 | # ldap.user.realNameAttribute=name 217 | 218 | # Attribute in LDAP defining the user’s email. (default: mail) 219 | # ldap.user.emailAttribute=email 220 | 221 | # GROUP MAPPING 222 | 223 | # Distinguished Name (DN) of the root node in LDAP from which to search for groups. (optional, default: empty) 224 | ldap.group.baseDn=ou=groups,dc=qualitysphere,dc=github,dc=io 225 | 226 | # LDAP group request (default: (&(objectClass=groupOfUniqueNames)(uniqueMember={dn})) ) 227 | # ldap.group.request=(&(objectClass=group)(member={dn})) 228 | 229 | # Property used to specifiy the attribute to be used for returning the list of user groups in the compatibility mode. (default: cn) 230 | # ldap.group.idAttribute=sAMAccountName 231 | 232 | #-------------------------------------------------------------------------------------------------- 233 | # COMPUTE ENGINE 234 | # The Compute Engine is responsible for processing background tasks. 235 | # Compute Engine is executed in a dedicated Java process. Default heap size is 512MB. 236 | # Use the following property to customize JVM options. 237 | # Recommendations: 238 | # 239 | # The HotSpot Server VM is recommended. The property -server should be added if server mode 240 | # is not enabled by default on your environment: 241 | # http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html 242 | # 243 | #sonar.ce.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError 244 | 245 | # Same as previous property, but allows to not repeat all other settings like -Xmx 246 | #sonar.ce.javaAdditionalOpts= 247 | 248 | 249 | #-------------------------------------------------------------------------------------------------- 250 | # ELASTICSEARCH 251 | # Elasticsearch is used to facilitate fast and accurate information retrieval. 252 | # It is executed in a dedicated Java process. Default heap size is 512MB. 253 | # 254 | # -------------------------------------------------- 255 | # Word of caution for Linux users on 64bits systems 256 | # -------------------------------------------------- 257 | # Please ensure Virtual Memory on your system is correctly configured for Elasticsearch to run properly 258 | # (see https://www.elastic.co/guide/en/elasticsearch/reference/5.5/vm-max-map-count.html for details). 259 | # 260 | # When SonarQube runs standalone, a warning such as the following may appear in logs/es.log: 261 | # "max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]" 262 | # When SonarQube runs as a cluster, however, Elasticsearch will refuse to start. 263 | # 264 | 265 | # JVM options of Elasticsearch process 266 | #sonar.search.javaOpts=-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError 267 | 268 | # Same as previous property, but allows to not repeat all other settings like -Xmx 269 | #sonar.search.javaAdditionalOpts= 270 | 271 | # Elasticsearch port. Default is 9001. Use 0 to get a free port. 272 | # As a security precaution, should be blocked by a firewall and not exposed to the Internet. 273 | #sonar.search.port=9001 274 | 275 | # Elasticsearch host. The search server will bind this address and the search client will connect to it. 276 | # Default is loopback address. 277 | # As a security precaution, should NOT be set to a publicly available address. 278 | #sonar.search.host= 279 | 280 | 281 | #-------------------------------------------------------------------------------------------------- 282 | # UPDATE CENTER 283 | 284 | # Update Center requires an internet connection to request https://update.sonarsource.org 285 | # It is enabled by default. 286 | #sonar.updatecenter.activate=true 287 | 288 | # HTTP proxy (default none) 289 | #http.proxyHost= 290 | #http.proxyPort= 291 | # HTTPS proxy (defaults are values of http.proxyHost and http.proxyPort) 292 | #https.proxyHost= 293 | #https.proxyPort= 294 | 295 | # NT domain name if NTLM proxy is used 296 | #http.auth.ntlm.domain= 297 | 298 | # SOCKS proxy (default none) 299 | #socksProxyHost= 300 | #socksProxyPort= 301 | 302 | # Proxy authentication (used for HTTP, HTTPS and SOCKS proxies) 303 | #http.proxyUser= 304 | #http.proxyPassword= 305 | 306 | # Proxy exceptions: list of hosts that can be accessed without going through the proxy 307 | # separated by the '|' character, wildcard character '*' can be used for pattern matching 308 | # used for HTTP and HTTPS (default none) 309 | # (note: localhost and its literal notations (127.0.0.1, ...) are always excluded) 310 | #http.nonProxyHosts= 311 | 312 | 313 | #-------------------------------------------------------------------------------------------------- 314 | # LOGGING 315 | 316 | # SonarQube produces logs in 4 logs files located in the same directory (see property sonar.path.logs below), 317 | # one per process: 318 | # Main process (aka. App) logs in sonar.log 319 | # Web Server (aka. Web) logs in web.log 320 | # Compute Engine (aka. CE) logs in ce.log 321 | # Elasticsearch (aka. ES) logs in es.log 322 | # 323 | # All 4 files follow the same rolling policy (see sonar.log.rollingPolicy and sonar.log.maxFiles) but it applies 324 | # individually (eg. if sonar.log.maxFiles=4, there can be at most 4 of each files, ie. 16 files in total). 325 | # 326 | # All 4 files have logs in the same format: 327 | # 1 2 3 4 5 6 328 | # |-----------------| |---| |-|--------------------||------------------------------| |------------------------------------------------------------------------------------------------------------------------------| 329 | # 2016.11.16 16:47:00 INFO ce[AVht0dNXFcyiYejytc3m][o.s.s.c.t.CeWorkerCallableImpl] Executed task | project=org.sonarqube:example-java-maven | type=REPORT | id=AVht0dNXFcyiYejytc3m | submitter=admin | time=1699ms 330 | # 331 | # 1: timestamp. Format is YYYY.MM.DD HH:MM:SS 332 | # YYYY: year on 4 digits 333 | # MM: month on 2 digits 334 | # DD: day on 2 digits 335 | # HH: hour of day on 2 digits in 24 hours format 336 | # MM: minutes on 2 digits 337 | # SS: seconds on 2 digits 338 | # 2: log level. 339 | # Possible values (in order of descending criticality): ERROR, WARN, INFO, DEBUG and TRACE 340 | # 3: process identifier. Possible values: app (main), web (Web Server), ce (Compute Engine) and es (Elasticsearch) 341 | # 4: SQ thread identifier. Can be empty. 342 | # In the Web Server, if present, it will be the HTTP request ID. 343 | # In the Compute Engine, if present, it will be the task ID. 344 | # 5: logger name. Usually a class canonical name. 345 | # Package names are truncated to keep the whole field to 20 characters max 346 | # 6: log payload. Content of this field does not follow any specific format, can vary in length and include line returns. 347 | # Some logs, however, will follow the convention to provide data in payload in the format " | key=value" 348 | # Especially, log of profiled pieces of code will end with " | time=XXXXms". 349 | 350 | # Global level of logs (applies to all 4 processes). 351 | # Supported values are INFO (default), DEBUG and TRACE 352 | #sonar.log.level=INFO 353 | 354 | # Level of logs of each process can be controlled individually with their respective properties. 355 | # When specified, they overwrite the level defined at global level. 356 | # Supported values are INFO, DEBUG and TRACE 357 | #sonar.log.level.app=INFO 358 | #sonar.log.level.web=INFO 359 | #sonar.log.level.ce=INFO 360 | #sonar.log.level.es=INFO 361 | 362 | # Path to log files. Can be absolute or relative to installation directory. 363 | # Default is /logs 364 | #sonar.path.logs=logs 365 | 366 | # Rolling policy of log files 367 | # - based on time if value starts with "time:", for example by day ("time:yyyy-MM-dd") 368 | # or by month ("time:yyyy-MM") 369 | # - based on size if value starts with "size:", for example "size:10MB" 370 | # - disabled if value is "none". That needs logs to be managed by an external system like logrotate. 371 | #sonar.log.rollingPolicy=time:yyyy-MM-dd 372 | 373 | # Maximum number of files to keep if a rolling policy is enabled. 374 | # - maximum value is 20 on size rolling policy 375 | # - unlimited on time rolling policy. Set to zero to disable old file purging. 376 | #sonar.log.maxFiles=7 377 | 378 | # Access log is the list of all the HTTP requests received by server. If enabled, it is stored 379 | # in the file {sonar.path.logs}/access.log. This file follows the same rolling policy as other log file 380 | # (see sonar.log.rollingPolicy and sonar.log.maxFiles). 381 | #sonar.web.accessLogs.enable=true 382 | 383 | # Format of access log. It is ignored if sonar.web.accessLogs.enable=false. Possible values are: 384 | # - "common" is the Common Log Format, shortcut to: %h %l %u %user %date "%r" %s %b 385 | # - "combined" is another format widely recognized, shortcut to: %h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" 386 | # - else a custom pattern. See http://logback.qos.ch/manual/layouts.html#AccessPatternLayout. 387 | # The login of authenticated user is not implemented with "%u" but with "%reqAttribute{LOGIN}" (since version 6.1). 388 | # The value displayed for anonymous users is "-". 389 | # The SonarQube's HTTP request ID can be added to the pattern with "%reqAttribute{ID}" (since version 6.2). 390 | # If SonarQube is behind a reverse proxy, then the following value allows to display the correct remote IP address: 391 | #sonar.web.accessLogs.pattern=%i{X-Forwarded-For} %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" "%reqAttribute{ID}" 392 | # Default value (which was "combined" before version 6.2) is equivalent to "combined + SQ HTTP request ID": 393 | #sonar.web.accessLogs.pattern=%h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" "%reqAttribute{ID}" 394 | 395 | 396 | #-------------------------------------------------------------------------------------------------- 397 | # OTHERS 398 | 399 | # Delay in seconds between processing of notification queue. Default is 60 seconds. 400 | #sonar.notifications.delay=60 401 | 402 | # Paths to persistent data files (embedded database and search index) and temporary files. 403 | # Can be absolute or relative to installation directory. 404 | # Defaults are respectively /data and /temp 405 | #sonar.path.data=data 406 | #sonar.path.temp=temp 407 | 408 | # Telemetry - Share anonymous SonarQube statistics 409 | # By sharing anonymous SonarQube statistics, you help us understand how SonarQube is used so we can improve the product to work even better for you. 410 | # We don't collect source code or IP addresses. And we don't share the data with anyone else. 411 | # To see an example of the data shared: login as a global administrator, call the WS api/system/info and check the Statistics field. 412 | #sonar.telemetry.enable=true 413 | 414 | 415 | #-------------------------------------------------------------------------------------------------- 416 | # DEVELOPMENT - only for developers 417 | # The following properties MUST NOT be used in production environments. 418 | 419 | # Elasticsearch HTTP connector 420 | #sonar.search.httpPort=-1 421 | -------------------------------------------------------------------------------- /odo-portal/dockerBuild/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /odoctl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -ex 3 | COMPOSE_YAML='docker-compose.yaml' 4 | COMPOSE_PROJECT='odo' 5 | DOCKER_COMPOSE="docker-compose --compatibility -f ${COMPOSE_YAML} -p ${COMPOSE_PROJECT}" 6 | COMPOSE_CONFIG=$(cat ${COMPOSE_YAML}) 7 | LDAP_DOMAIN=$(echo $COMPOSE_CONFIG | awk -F 'container_name: odo-ldap-openldap' '{print $2}' | awk -F 'SLAPD_DOMAIN: ' '{print $2}' | awk '{print $1}') 8 | LDAP_ADMIN="cn=admin,dc=$(echo $LDAP_DOMAIN | sed 's/\./,dc=/g')" 9 | LDAP_PASSWD=$(echo $COMPOSE_CONFIG | awk -F 'container_name: odo-ldap-openldap' '{print $2}' | awk -F 'SLAPD_PASSWORD: ' '{print $2}' | awk '{print $1}') 10 | PG_USER=$(echo $COMPOSE_CONFIG | awk -F 'container_name: odo-pg' '{print $2}' | awk -F 'POSTGRES_USER: ' '{print $2}' | awk '{print $1}') 11 | PG_PASSWD=$(echo $COMPOSE_CONFIG | awk -F 'container_name: odo-pg' '{print $2}' | awk -F 'POSTGRES_PASSWORD: ' '{print $2}' | awk '{print $1}') 12 | 13 | COMPOSE_CMD="${1-''}" 14 | COMPOSE_SVC="${2-''}" 15 | PRODUCT_ID="${3}" 16 | ODO_HOME=$PWD 17 | 18 | ODO_INIT_PG='yes' 19 | ODO_INIT_LDAP='yes' 20 | ODO_INIT_JENKINS='yes' 21 | ODO_INIT_SONAR='yes' 22 | ODO_INIT_JIRA='yes' 23 | ODO_INIT_CONF='yes' 24 | ODO_INIT_GITLAB='yes' 25 | ODO_INIT_HARBOR='yes' 26 | ODO_INIT_RANCHER='yes' 27 | ODO_INIT_JMS='yes' 28 | 29 | COOKIES=".odo_cookies" 30 | CURL="curl -s -v --location -c ${COOKIES} -b ${COOKIES}" 31 | 32 | ## Common Function 33 | function log_error() { 34 | echo -e "\033[33;1m$@ \033[0m" 35 | exit 1 36 | } 37 | 38 | function log_fail() { 39 | echo -e "\033[31;1m[FAIL] Whoops! Looks like we have some trouble ...\033[0m" 40 | echo -e "$@" 41 | exit 1 42 | } 43 | 44 | function chmod_dir() { 45 | dir_name=$1 46 | while true; do 47 | sleep 1 48 | [[ -d ${dir_name} ]] && break 49 | done 50 | chmod -R 777 ${dir_name} 51 | } 52 | 53 | ## ODO Document 54 | function help_doc_cmd() { 55 | cat <: 57 | start - Up container(s) to start service(s) and init them 58 | start_no_init - Up container(s) to start service(s) 59 | stop - Stop container(s) to stop service(s) 60 | down - Down all services 61 | restart - Restart container(s) to restart service(s) 62 | list - List container(s) 63 | license - Generate JIRA/Confluence/Plugin license 64 | cleanup - Cleanup all containers and dirs 65 | EOF 66 | exit 1 67 | } 68 | 69 | function help_doc_svc() { 70 | cat <: 72 | all - All Services 73 | ldap - OpenLDAP, PhpLDAPAdmin and Self Service Password 74 | pg - PostgresQL 75 | jira - Jira Software 76 | conf - Confluence 77 | sonar - SonarQube Community Edition 78 | jenkins - Jenkins 79 | gitlab - GitLab Community Edition 80 | harbor - Harbor 81 | rancher - Rancher 82 | jms - JumpServer 83 | portal - DevOps Portal 84 | EOF 85 | exit 1 86 | } 87 | 88 | function help_doc_license() { 89 | cat <: 91 | jira - Generate JIRA software license 92 | jira_plugin - Generate JIRA plugin license 93 | conf - Generate Confluence server license 94 | conf_plugin - Generate Confluence plugin license 95 | jenkins - Get Jenkins initialAdminPassword 96 | EOF 97 | exit 1 98 | } 99 | 100 | function help_doc_license_pid() { 101 | cat <: 103 | PRODUCT_ID is REQUIRED 104 | +-------------+------------+------------------------------------+ 105 | | PRODUCT | PRODUCT_ID | WHERE | 106 | +-------------+------------+------------------------------------+ 107 | | jira_plugin | plugin ID | JIRA application detail page | 108 | +-------------+------------+------------------------------------+ 109 | | conf | server ID | Confluence installation page | 110 | +-------------+------------+------------------------------------+ 111 | | conf_plugin | plugin ID | Confluence application detail page | 112 | +-------------+------------+------------------------------------+ 113 | EOF 114 | exit 0 115 | } 116 | 117 | ## ODO Basic Function 118 | function check_env() { 119 | [[ "$(uname)" == "Linux" ]] || log_error "Only support Linux OS" 120 | [[ -f /etc/selinux/config ]] && { 121 | [[ "$(getenforce)" == "Enforcing" ]] && setenforce 0 122 | sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config 123 | } 124 | for _tool in "docker" "docker-compose" "curl"; do 125 | output=$(${_tool} --version 2>&1) || { 126 | echo -e "\033[33;1m${_tool} is required in this machine \033[0m" 127 | echo "${output}" 128 | exit 1 129 | } 130 | done 131 | } 132 | 133 | function check_odo_cli() { 134 | echo "start start_no_init stop down restart list license cleanup" | grep -qw "${COMPOSE_CMD}" || help_doc_cmd 135 | if [[ "${COMPOSE_CMD}" == "license" ]]; then 136 | echo "jira jira_plugin conf conf_plugin jenkins" | grep -qw "${COMPOSE_SVC}" || help_doc_license 137 | [[ "${COMPOSE_SVC}" == "jira" ]] && return 0 138 | [[ "${COMPOSE_SVC}" == "jenkins" ]] && return 0 139 | [[ -z "${PRODUCT_ID}" ]] && help_doc_license_pid 140 | elif [[ "${COMPOSE_CMD}" == "list" ]]; then 141 | return 0 142 | elif [[ "${COMPOSE_CMD}" == "cleanup" ]]; then 143 | return 0 144 | elif [[ "${COMPOSE_CMD}" == "down" ]]; then 145 | return 0 146 | else 147 | echo "all ldap pg jira conf sonar jenkins gitlab rancher jms portal harbor" | grep -qw "${COMPOSE_SVC}" || help_doc_svc 148 | fi 149 | return 0 150 | } 151 | 152 | function check_odo_svc() { 153 | if [[ "${COMPOSE_SVC}" == "all" ]]; then 154 | COMPOSE_SVC="" 155 | elif [[ "${COMPOSE_SVC}" == "ldap" ]]; then 156 | COMPOSE_SVC="odo-ldap-openldap odo-ldap-phpldapadmin odo-ldap-ssp" 157 | else 158 | [[ "${COMPOSE_CMD}" == "license" ]] || COMPOSE_SVC="odo-${COMPOSE_SVC}" 159 | fi 160 | } 161 | 162 | function check_odo_exist() { 163 | [[ -d odo-pg ]] && ODO_INIT_PG='no' 164 | [[ -d odo-ldap/db ]] && ODO_INIT_LDAP='no' 165 | [[ -d odo-jenkins ]] && ODO_INIT_JENKINS='no' 166 | [[ -d odo-sonar/data ]] && ODO_INIT_SONAR='no' 167 | [[ -d odo-jira ]] && ODO_INIT_JIRA='no' 168 | [[ -d odo-conf ]] && ODO_INIT_CONF='no' 169 | [[ -d odo-gitlab/config ]] && ODO_INIT_GITLAB='no' 170 | [[ -f odo-harbor/docker-compose.yml ]] && ODO_INIT_HARBOR='no' 171 | [[ -d odo-rancher ]] && ODO_INIT_RANCHER='no' 172 | [[ -d odo-jms/data ]] && ODO_INIT_JMS='no' 173 | return 0 174 | } 175 | 176 | # Usage: get_odo_service_port container_name 177 | function get_odo_service_port() { 178 | echo ${COMPOSE_CONFIG} | awk -F "container_name: $1" '{print $2}' | awk -F 'ports: - ' '{print $2}' | awk -F ':' '{print $1}' 179 | return 0 180 | } 181 | 182 | ## ODO Init Service Function 183 | function set_host_for_sonar() { 184 | [[ "${ODO_INIT_SONAR}" == "yes" ]] || return 0 185 | [[ "$(uname)" == "Linux" ]] && { 186 | sysctl -w vm.max_map_count=262144 187 | sysctl -w fs.file-max=65535 188 | ulimit -n 65535 189 | ulimit -u 4095 190 | } 191 | } 192 | 193 | function init_odo_pg() { 194 | [[ "${ODO_INIT_PG}" == "yes" ]] || return 0 195 | echo "Waiting for PostgresQL running ..." 196 | chmod_dir odo-pg 197 | while true; do 198 | sleep 1 199 | docker exec -it odo-pg psql -U postgres -l && break 200 | done 201 | db_list=$(docker exec -it odo-pg psql -U postgres -l) 202 | for db_name in jira conf sonar; do 203 | echo "Check and init DB for ${db_name}" 204 | echo "${db_list}" | grep $db_name || docker exec -it odo-pg createdb -U postgres $db_name 205 | done 206 | echo "Complete to init DB" 207 | docker exec -it odo-pg psql -U postgres -l 208 | } 209 | 210 | function init_odo_ldap() { 211 | [[ "${ODO_INIT_LDAP}" == "yes" ]] || return 0 212 | phpldapadmin_url=$(grep ODO_PHPLADPADMIN_URL docker-compose.yaml | awk '{print $NF}') 213 | [[ "${phpldapadmin_url}" == "" ]] && phpldapadmin_url="http://localhost:$(get_odo_service_port odo-ldap-phpldapadmin)" 214 | phpldapadmin_index_url="${phpldapadmin_url}/htdocs/index.php" 215 | phpldapadmin_cmd_url="${phpldapadmin_url}/htdocs/cmd.php" 216 | _curl_output=".ldapcontent" 217 | echo "Access LDAP: ${phpldapadmin_index_url}" 218 | while true; do 219 | sleep 2 220 | rm -rf ${COOKIES} 221 | output=$($CURL -X GET "$phpldapadmin_index_url" -o ${_curl_output} 2>&1) 222 | echo "$output" | grep HTTP | grep 200 && break 223 | done 224 | echo "Login LDAP: ${phpldapadmin_cmd_url}" 225 | output=$($CURL -X POST "$phpldapadmin_cmd_url" \ 226 | -H 'Accept: */*' \ 227 | -H 'Content-Type: application/x-www-form-urlencoded' \ 228 | --data-urlencode 'cmd=login' \ 229 | --data-urlencode 'server_id=1' \ 230 | --data-urlencode 'nodecode[login_pass]=1' \ 231 | --data-urlencode "login=${LDAP_ADMIN}" \ 232 | --data-urlencode "login_pass=${LDAP_PASSWD}" \ 233 | --data-urlencode 'submit=Authenticate' \ 234 | -o ${_curl_output} 2>&1) 235 | echo "$output" | grep HTTP | grep 200 || log_fail "$output" 236 | echo "Import LDAP: ${phpldapadmin_cmd_url}" 237 | output=$($CURL -X POST "$phpldapadmin_cmd_url" \ 238 | -H 'Accept: */*' \ 239 | -H 'Content-Type: multipart/form-data' \ 240 | --form 'server_id=1' \ 241 | --form 'cmd=import' \ 242 | --form "ldif=$(cat odo-ldap/odo_users.ldif)" \ 243 | -o ${_curl_output} 2>&1) 244 | echo "$output" | grep HTTP | grep 200 || log_fail "$output" 245 | rm -rf ${_curl_output} 246 | rm -rf ${COOKIES} 247 | return 0 248 | } 249 | 250 | function init_odo_sonar() { 251 | [[ "${ODO_INIT_SONAR}" == "yes" ]] || return 0 252 | chmod_dir odo-sonar 253 | sonar_url=$(grep ODO_SONAR_URL docker-compose.yaml | awk '{print $NF}') 254 | [[ "${sonar_url}" == "" ]] && sonar_url="http://localhost:$(get_odo_service_port odo-sonar)}" 255 | sonar_status_url="${sonar_url}/api/system/status" 256 | sonar_login_url="${sonar_url}/api/authentication/login" 257 | sonar_plugin_url="${sonar_url}/api/plugins/install" 258 | sonar_restart_url="${sonar_url}/api/system/restart" 259 | echo "Waiting for SonarQube[${sonar_url}] running ..." 260 | while true; do 261 | sleep 2 262 | rm -rf ${COOKIES} 263 | $CURL -X GET ${sonar_status_url} 2>&1 | grep HTTP | grep 200 && break 264 | done 265 | echo "Login SonarQube[${sonar_login_url}] ..." 266 | while true; do 267 | sleep 2 268 | rm -rf ${COOKIES} 269 | output=$($CURL -X POST ${sonar_login_url} \ 270 | -H 'Accept: application/json' \ 271 | -H 'Content-Type: application/x-www-form-urlencoded' \ 272 | --data-urlencode "login=admin" \ 273 | --data-urlencode "password=admin" \ 274 | 2>&1) 275 | echo "${output}" | grep HTTP | grep 200 && { 276 | sonar_token=$(echo "${output}" | grep ' Set-Cookie:' | grep 'XSRF-TOKEN=' | awk -F 'XSRF-TOKEN=' '{print $2}' | awk -F ';' '{print $1}') 277 | [[ -z "${sonar_token}" ]] && exit 1 278 | echo "${sonar_token}" 279 | break 280 | } 281 | done 282 | echo "Install LDAP plugin: ${sonar_plugin_url}" 283 | output=$($CURL -X POST ${sonar_plugin_url} \ 284 | -H 'Accept: application/json' \ 285 | -H 'Content-Type: application/x-www-form-urlencoded' \ 286 | -H "X-XSRF-TOKEN: ${sonar_token}" \ 287 | --data-urlencode 'key=ldap' \ 288 | 2>&1) 289 | echo "${output}" | grep HTTP | grep 204 || log_fail "${output}" 290 | echo "Update sonar.properties to enable LDAP" 291 | sed -i 's/#sonar.security.realm=LDAP/sonar.security.realm=LDAP/' odo-sonar/sonar.properties 292 | echo "Restart sonar: ${sonar_restart_url}" 293 | output=$($CURL -X POST ${sonar_restart_url} \ 294 | -H 'Accept: application/json' \ 295 | -H 'Content-Type: application/x-www-form-urlencoded' \ 296 | -H "X-XSRF-TOKEN: ${sonar_token}" \ 297 | 2>&1) 298 | echo "${output}" | grep HTTP | grep 200 || log_fail "$output" 299 | rm -rf ${COOKIES} 300 | docker restart odo-sonar 301 | return 0 302 | } 303 | 304 | function init_odo_jenkins() { 305 | [[ "${ODO_INIT_JENKINS}" == "yes" ]] || return 0 306 | chmod_dir odo-jenkins 307 | return 0 308 | ## Need more debug 309 | jenkins_url=$(grep ODO_JENKINS_URL docker-compose.yaml | awk '{print $NF}') 310 | [[ "${jenkins_url}" == "" ]] && jenkins_url="http://localhost:$(get_odo_service_port odo-jenkins)" 311 | jenkins_login_url="${jenkins_url}/login" 312 | jenkins_security_url="${jenkins_url}/j_acegi_security_check" 313 | jenkins_plugin_url="${jenkins_url}/pluginManager/installPlugins" 314 | jenkins_restart_url="${jenkins_url}/updateCenter/safeRestart" 315 | echo "Waiting for Jenkins[${jenkins_login_url}] running ..." 316 | while true; do 317 | sleep 2 318 | rm -rf ${COOKIES} 319 | output=$($CURL -X GET "${jenkins_login_url}" 2>&1) 320 | echo "${output}" | grep HTTP | grep -E '200|302' && break 321 | done 322 | echo "Unlock Jenkins: ${jenkins_security_url}" 323 | j_password=$(docker exec -it odo-jenkins sh -c 'cat /var/jenkins_home/secrets/initialAdminPassword' | sed 's/\r//g') 324 | j_crumb=$(echo "$output" | grep '"Jenkins-Crumb"' | awk -F '"Jenkins-Crumb"' '{print $2}' | awk -F '"' '{print $2}') 325 | output=$($CURL -X POST "${jenkins_security_url}" \ 326 | -H 'Accept: */*' \ 327 | -H 'Content-Type: application/x-www-form-urlencoded' \ 328 | --data-urlencode 'from=/' \ 329 | --data-urlencode 'j_username=admin' \ 330 | --data-urlencode "j_password=${j_password}" \ 331 | --data-urlencode "Jenkins-Crumb=${j_crumb}" \ 332 | --data-urlencode "json={\"from\":\"\",\"j_username\":\"admin\",\"j_password\":\"${j_password}\",\"\$redact\":\"j_password\",\"Jenkins-Crumb\":\"${j_crumb}\"}" \ 333 | 2>&1) 334 | echo "${output}" | grep HTTP | grep 200 || log_fail "${output}" 335 | echo "Install Plugins: ${jenkins_plugin_url}" 336 | j_crumb=$(echo "$output" | grep '"Jenkins-Crumb"' | awk -F '"Jenkins-Crumb"' '{print $2}' | awk -F '"' '{print $2}') 337 | output=$($CURL -X POST "${jenkins_security_url}" \ 338 | -H 'Accept: */*' \ 339 | -H 'Content-Type: application/x-www-form-urlencoded' \ 340 | --data-urlencode "Jenkins-Crumb=${j_crumb}" \ 341 | --data-urlencode 'dynamicLoad=true' \ 342 | --data-urlencode 'plugins=["cloudbees-folder","antisamy-markup-formatter","build-timeout","credentials-binding","timestamper","ws-cleanup","workflow-aggregator","pipeline-stage-view","git","subversion","ssh-slaves","matrix-auth","pam-auth","ldap","email-ext","mailer","localization-zh-cn","htmlpublisher","gitlab-plugin","git-parameter","authorize-project","publish-over-ssh","emailext-template","ssh"]' \ 343 | 2>&1) 344 | echo "${output}" | grep HTTP | grep 200 || log_fail "${output}" 345 | echo "Restart Jenkins: ${jenkins_restart_url}" 346 | j_crumb=$(echo "$output" | grep '"Jenkins-Crumb"' | awk -F '"Jenkins-Crumb"' '{print $2}' | awk -F '"' '{print $2}') 347 | output=$($CURL -X POST "${jenkins_restart_url}" \ 348 | -H 'Accept: */*' \ 349 | -H 'Content-Type: application/x-www-form-urlencoded' \ 350 | --data-urlencode "Jenkins-Crumb=${j_crumb}" \ 351 | 2>&1) 352 | echo "${output}" | grep HTTP | grep 200 || log_fail "${output}" 353 | return 0 354 | } 355 | 356 | function init_odo_jira() { 357 | [[ "${ODO_INIT_JIRA}" == "yes" ]] || return 0 358 | jira_url=$(grep ODO_JIRA_URL docker-compose.yaml | awk '{print $NF}') 359 | [[ "${jira_url}" == "" ]] && jira_url="http://localhost:$(get_odo_service_port odo-jira)" 360 | jira_mode_url="${jira_url}/secure/SetupMode.jspa" 361 | jira_db_url="${jira_url}/secure/SetupDatabase.jspa" 362 | jira_app_url="${jira_url}/secure/SetupApplicationProperties.jspa" 363 | jira_license_url="${jira_url}/secure/SetupLicense.jspa" 364 | jira_admin_url="${jira_url}/secure/SetupAdminAccount.jspa" 365 | jira_mail_url="${jira_url}/secure/SetupMailNotifications.jspa" 366 | echo "Waiting for Jira Software[${jira_url}] running ..." 367 | while true; do 368 | sleep 2 369 | rm -rf ${COOKIES} 370 | output=$($CURL -X GET "${jira_url}" 2>&1) 371 | echo "${output}" | grep HTTP | grep -E '200|302' && { 372 | atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 373 | echo "${atl_token}" 374 | [[ -z "${atl_token}" ]] || break 375 | } 376 | done 377 | echo "Setup Mode: ${jira_mode_url}" 378 | output=$($CURL -X POST ${jira_mode_url} \ 379 | -H 'Accept: */*' \ 380 | -H 'Content-Type: application/x-www-form-urlencoded' \ 381 | --data-urlencode 'setupOption=classic' \ 382 | --data-urlencode "atl_token=${atl_token}" \ 383 | 2>&1) 384 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 385 | echo "Setup Database: ${jira_db_url}" 386 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 387 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 388 | output=$($CURL -X POST ${jira_db_url} \ 389 | -H 'Accept: */*' \ 390 | -H 'Content-Type: application/x-www-form-urlencoded' \ 391 | --data-urlencode 'databaseOption=external' \ 392 | --data-urlencode 'databaseType=postgres72' \ 393 | --data-urlencode 'jdbcHostname=odo-pg' \ 394 | --data-urlencode 'jdbcPort=5432' \ 395 | --data-urlencode 'jdbcDatabase=jira' \ 396 | --data-urlencode 'jdbcSid=' \ 397 | --data-urlencode "jdbcUsername=${PG_USER}" \ 398 | --data-urlencode "jdbcPassword=${PG_PASSWD}" \ 399 | --data-urlencode 'schemaName=public' \ 400 | --data-urlencode "atl_token=${atl_token}" \ 401 | 2>&1) 402 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 403 | echo "Setup Application Properties: ${jira_app_url}" 404 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 405 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 406 | output=$($CURL -X POST ${jira_url}/secure/SetupApplicationProperties.jspa \ 407 | -H 'Accept: */*' \ 408 | -H 'Content-Type: application/x-www-form-urlencoded' \ 409 | --data-urlencode 'title=Jira' \ 410 | --data-urlencode 'mode=private' \ 411 | --data-urlencode "baseURL=${jira_url}" \ 412 | --data-urlencode 'nextStep=true' \ 413 | --data-urlencode "atl_token=${atl_token}" \ 414 | 2>&1) 415 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 416 | echo "Generate Jira Software License" 417 | jira_license=$(docker exec -it odo-jira getJiraLicense | tail -9) 418 | echo "${jira_license}" 419 | echo "Setup Jira Software License: ${jira_license_url}" 420 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 421 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 422 | output=$($CURL -X POST "${jira_url}/secure/SetupLicense!validateLicense.jspa" \ 423 | -H 'Accept: */*' \ 424 | -H 'Content-Type: application/x-www-form-urlencoded' \ 425 | --data-urlencode "licenseToValidate=${jira_license}" \ 426 | 2>&1) 427 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 428 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 429 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 430 | output=$($CURL -X POST ${jira_license_url} \ 431 | -H 'Accept: */*' \ 432 | -H 'Content-Type: application/x-www-form-urlencoded' \ 433 | --data-urlencode "setupLicenseKey=${jira_license}" \ 434 | --data-urlencode "atl_token=${atl_token}" \ 435 | 2>&1) 436 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 437 | echo "Setup Admin Account: ${jira_admin_url}" 438 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 439 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 440 | output=$($CURL -X POST ${jira_admin_url} \ 441 | -H 'Accept: */*' \ 442 | -H 'Content-Type: application/x-www-form-urlencoded' \ 443 | --data-urlencode "fullname=admin" \ 444 | --data-urlencode "email=admin@${LDAP_DOMAIN}" \ 445 | --data-urlencode "username=admin" \ 446 | --data-urlencode "password=${LDAP_PASSWD}" \ 447 | --data-urlencode "confirm=${LDAP_PASSWD}" \ 448 | --data-urlencode "atl_token=${atl_token}" \ 449 | 2>&1) 450 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 451 | echo "Setup Mail Notifications: ${jira_mail_url}" 452 | get_atl_token=$(echo "${output}" | grep 'Set-Cookie: ' | awk -F 'Set-Cookie: ' '{print $NF}' | awk -F 'atlassian.xsrf.token=' '{print $2}' | awk -F ';' '{print $1}') 453 | [[ -z "$get_atl_token" ]] || atl_token=$get_atl_token 454 | output=$($CURL -X POST ${jira_mail_url} \ 455 | -H 'Accept: */*' \ 456 | -H 'Content-Type: application/x-www-form-urlencoded' \ 457 | --data-urlencode "analytics-enabled=" \ 458 | --data-urlencode "noemail=true" \ 459 | --data-urlencode "name=admin" \ 460 | --data-urlencode "from=opendevops" \ 461 | --data-urlencode "prefix=[Jira]" \ 462 | --data-urlencode "mailservertype=smtp" \ 463 | --data-urlencode "serverProvider=custom" \ 464 | --data-urlencode "serverName=" \ 465 | --data-urlencode "protocol=smtp" \ 466 | --data-urlencode "port=" \ 467 | --data-urlencode "timeout=10000" \ 468 | --data-urlencode "username=" \ 469 | --data-urlencode "password=" \ 470 | --data-urlencode "jndiLocation=" \ 471 | --data-urlencode "type=smtp" \ 472 | --data-urlencode "testingMailConnection=false" \ 473 | --data-urlencode "atl_token=${atl_token}" \ 474 | 2>&1) 475 | echo "${output}" | grep HTTP | grep -E '200|302' || log_fail "$output" 476 | rm -rf ${COOKIES} 477 | return 0 478 | } 479 | 480 | function init_odo_conf() { 481 | [[ "${ODO_INIT_CONF}" == "yes" ]] || return 0 482 | conf_url=$(grep ODO_CONF_URL docker-compose.yaml | awk '{print $NF}') 483 | [[ "${conf_url}" == "" ]] && conf_url="http://localhost:$(get_odo_service_port odo-conf)" 484 | conf_start_url="${conf_url}/setup/dosetupstart.action" 485 | conf_bundle_url="${conf_url}/setup/doselectbundle.action" 486 | conf_license_url="${conf_url}/setup/dosetuplicense.action" 487 | conf_dbchoice_url="${conf_url}/setup/setupdbchoice.action" 488 | conf_dbtest_url="${conf_url}/setup/setupstandarddb-testconnection.action" 489 | conf_dbtype_url="${conf_url}/setup/setupdbtype.action" 490 | conf_data_url="${conf_url}/setup/setupdata.action" 491 | conf_user_url="${conf_url}/setup/setupusermanagementchoice.action" 492 | conf_admin_url="${conf_url}/setup/setupadministrator.action" 493 | echo "Waiting for Confluence Server[${conf_url}] running ..." 494 | while true 495 | do 496 | sleep 2 497 | rm -rf ${COOKIES} 498 | output=$($CURL -X GET ${conf_url}/setup/setupstart.action 2>&1) 499 | echo "${output}" | grep HTTP | grep -E '302|200' && { 500 | atl_token=$(echo "${output}" | grep Location | awk -F 'atl_token=' '{print $2}' | sed 's/\r//g') 501 | [[ -z "$atl_token" ]] || break 502 | } 503 | done 504 | echo "Start Setup Confluence: ${conf_start_url}" 505 | output=$($CURL -X GET "${conf_start_url}?setupType=custom&atl_token=${atl_token}" 2>&1) 506 | echo "$output" | grep HTTP | grep -E '302|200' || log_fail "$output" 507 | echo "Select Bundle: ${conf_bundle_url}" 508 | output=$($CURL -X POST ${conf_bundle_url} \ 509 | -H 'Accept: */*' \ 510 | -H 'Content-Type: application/x-www-form-urlencoded' \ 511 | --data-urlencode 'pluginKeys=' \ 512 | --data-urlencode 'setup-next-button=Next' \ 513 | --data-urlencode "atl_token=${atl_token}" \ 514 | 2>&1) 515 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 516 | echo "Get server ID: ${conf_url}/setup/setuplicense.action" 517 | output=$($CURL -X GET ${conf_url}/setup/setuplicense.action 2>&1) 518 | echo "$output" | grep HTTP | grep -E '200|302' || log_error "$output" 519 | conf_server_id=$(echo "$output"| grep 'name="serverId"' | awk -F 'value=' '{print $2}' | awk -F '"' '{print $2}') 520 | echo "${conf_server_id}" 521 | echo "Generate conf license" 522 | conf_license=$(docker exec -it odo-conf getConfLicense ${conf_server_id} | tail -8) 523 | echo "$conf_license" 524 | echo "Setup license: ${conf_license_url}" 525 | output=$($CURL -X POST ${conf_license_url} \ 526 | -H 'Accept: */*' \ 527 | -H 'Content-Type: application/x-www-form-urlencoded' \ 528 | --data-urlencode "selectedPluginKeys=" \ 529 | --data-urlencode "confLicenseString=${conf_license}" \ 530 | --data-urlencode "setupTypeCustom=next" \ 531 | --data-urlencode "atl_token=${atl_token}" \ 532 | 2>&1) 533 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 534 | echo "Choice DB: ${conf_dbchoice_url}" 535 | output=$($CURL -X POST ${conf_dbchoice_url} \ 536 | -H 'Accept: */*' \ 537 | -H 'Content-Type: application/x-www-form-urlencoded' \ 538 | --data-urlencode "thisNodeClustered=false" \ 539 | --data-urlencode "dbChoice=custom" \ 540 | --data-urlencode "setup-next-button=Next" \ 541 | --data-urlencode "atl_token=${atl_token}" \ 542 | 2>&1) 543 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 544 | echo "Test DB: ${conf_dbtest_url}" 545 | output=$($CURL -X POST ${conf_dbtest_url} \ 546 | -H 'Accept: */*' \ 547 | -H 'Content-Type: application/x-www-form-urlencoded' \ 548 | --data-urlencode "dbConfigInfo.databaseType=postgresql" \ 549 | --data-urlencode "dbConfigInfo.simple=false" \ 550 | --data-urlencode "dbConfigInfo.databaseUrl=jdbc:postgresql://odo-pg:5432/conf" \ 551 | --data-urlencode "dbConfigInfo.hostname=" \ 552 | --data-urlencode "dbConfigInfo.port=" \ 553 | --data-urlencode "dbConfigInfo.databaseName=" \ 554 | --data-urlencode "dbConfigInfo.serviceName=" \ 555 | --data-urlencode "dbConfigInfo.userName=${PG_USER}" \ 556 | --data-urlencode "dbConfigInfo.password=${PG_PASSWD}" \ 557 | --data-urlencode "dbConfigInfo.instanceName=" \ 558 | --data-urlencode "database=" \ 559 | --data-urlencode "atl_token=${atl_token}" \ 560 | 2>&1) 561 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 562 | echo "Setup DB: ${conf_dbtype_url}" 563 | output=$($CURL -X POST ${conf_dbtype_url} \ 564 | -H 'Accept: */*' \ 565 | -H 'Content-Type: application/x-www-form-urlencoded' \ 566 | --data-urlencode "dbConfigInfo.databaseType=postgresql" \ 567 | --data-urlencode "dbConfigInfo.simple=false" \ 568 | --data-urlencode "dbConfigInfo.databaseUrl=jdbc:postgresql://odo-pg:5432/conf" \ 569 | --data-urlencode "dbConfigInfo.hostname=" \ 570 | --data-urlencode "dbConfigInfo.port=" \ 571 | --data-urlencode "dbConfigInfo.databaseName=" \ 572 | --data-urlencode "dbConfigInfo.serviceName=" \ 573 | --data-urlencode "dbConfigInfo.userName=${PG_USER}" \ 574 | --data-urlencode "dbConfigInfo.password=${PG_PASSWD}" \ 575 | --data-urlencode "dbConfigInfo.instanceName=" \ 576 | --data-urlencode "database=" \ 577 | --data-urlencode "atl_token=${atl_token}" \ 578 | 2>&1) 579 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 580 | echo "Setup Data: ${conf_data_url}" 581 | output=$($CURL -X POST ${conf_data_url} \ 582 | -H 'Accept: */*' \ 583 | -H 'Content-Type: application/x-www-form-urlencoded' \ 584 | --data-urlencode "dbchoiceSelect=Empty+Site" \ 585 | --data-urlencode "contentChoice=blank" \ 586 | --data-urlencode "atl_token=${atl_token}" \ 587 | 2>&1) 588 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 589 | echo "Setup User Management: ${conf_user_url}" 590 | output=$($CURL -X POST ${conf_user_url} \ 591 | -H 'Accept: */*' \ 592 | -H 'Content-Type: application/x-www-form-urlencoded' \ 593 | --data-urlencode "userManagementChoice=internal" \ 594 | --data-urlencode "internal=Manage+users+and+groups+within+Confluence" \ 595 | --data-urlencode "atl_token=${atl_token}" \ 596 | 2>&1) 597 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 598 | echo "Setup Administrator: ${conf_admin_url}" 599 | output=$($CURL -X POST ${conf_admin_url} \ 600 | -H 'Accept: */*' \ 601 | -H 'Content-Type: application/x-www-form-urlencoded' \ 602 | --data-urlencode "username=admin" \ 603 | --data-urlencode "fullName=admin" \ 604 | --data-urlencode "email=admin@${LDAP_DOMAIN}" \ 605 | --data-urlencode "password=${LDAP_PASSWD}" \ 606 | --data-urlencode "confirm=${LDAP_PASSWD}" \ 607 | --data-urlencode "step-next-button=Next" \ 608 | --data-urlencode "atl_token=${atl_token}" \ 609 | 2>&1) 610 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 611 | rm -rf ${COOKIES} 612 | return 0 613 | } 614 | 615 | function init_odo_gitlab() { 616 | [[ "${ODO_INIT_GITLAB}" == "yes" ]] || return 0 617 | gitlab_url=$(grep ODO_GITLAB_URL docker-compose.yaml | awk '{print $NF}') 618 | [[ "${gitlab_url}" == "" ]] && gitlab_url="http://localhost:$(get_odo_service_port odo-gitlab)" 619 | gitlab_passwd_url="${gitlab_url}/users/password" 620 | gitlab_login_url="${gitlab_url}/users/sign_in" 621 | gitlab_setting_url="${gitlab_url}/admin/application_settings/general" 622 | echo "Waiting for GitLab[${gitlab_url}] running ..." 623 | while true 624 | do 625 | sleep 2 626 | rm -rf ${COOKIES} 627 | output=$($CURL -X GET ${gitlab_url} 2>&1) 628 | echo "${output}" | grep HTTP | grep -E '302|200' && { 629 | reset_password_token=$(echo "${output}" | \ 630 | grep Location | \ 631 | grep 'reset_password_token' | \ 632 | awk -F 'reset_password_token=' '{print $2}' | \ 633 | sed 's/\r//g') 634 | auth_token=$(echo "$output" | \ 635 | grep 'name="authenticity_token"' | \ 636 | awk -F 'name="authenticity_token"' '{print $2}' | \ 637 | awk -F 'value="' '{print $2}' | \ 638 | awk -F '"' '{print $1}') 639 | [[ -z "$reset_password_token" ]] || { 640 | [[ -z "$auth_token" ]] || { 641 | echo "Auth Token: $auth_token" 642 | break 643 | } 644 | } 645 | } 646 | done 647 | echo "Reset GitLab password: ${gitlab_passwd_url}" 648 | output=$($CURL -X POST ${gitlab_passwd_url} \ 649 | -H 'Accept: */*' \ 650 | -H 'Content-Type: application/x-www-form-urlencoded' \ 651 | --data-urlencode "_method=put" \ 652 | --data-urlencode "authenticity_token=${auth_token}" \ 653 | --data-urlencode "user[reset_password_token]=${reset_password_token}" \ 654 | --data-urlencode "user[password]=${LDAP_PASSWD}" \ 655 | --data-urlencode "user[password_confirmation]=${LDAP_PASSWD}" \ 656 | 2>&1) 657 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 658 | echo "Login GitLab: ${gitlab_login_url}" 659 | output=$($CURL -X GET ${gitlab_login_url} 2>&1) 660 | echo "${output}" | grep HTTP | grep -E '302|200' && { 661 | auth_token=$(echo "$output" | \ 662 | grep 'action="/users/sign_in"' -A 5 | \ 663 | grep 'name="authenticity_token"' | \ 664 | awk -F 'name="authenticity_token"' '{print $2}' | \ 665 | awk -F 'value="' '{print $2}' | \ 666 | awk -F '"' '{print $1}') 667 | echo "Auth Token: $auth_token" 668 | } 669 | output=$($CURL -X POST ${gitlab_login_url} \ 670 | -H 'Accept: */*' \ 671 | -H 'Content-Type: application/x-www-form-urlencoded' \ 672 | --data-urlencode "authenticity_token=${auth_token}" \ 673 | --data-urlencode "user[login]=root" \ 674 | --data-urlencode "user[password]=${LDAP_PASSWD}" \ 675 | --data-urlencode "user[remember_me]=0" \ 676 | 2>&1) 677 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 678 | echo "Disable GitLab Sign Up: ${gitlab_setting_url}" 679 | output=$($CURL -X GET ${gitlab_setting_url} 2>&1) 680 | echo "${output}" | grep HTTP | grep -E '302|200' && { 681 | auth_token=$(echo "$output" | \ 682 | grep -A 5 'general#js-signup-settings' | \ 683 | grep 'name="authenticity_token"' | \ 684 | awk -F 'name="authenticity_token"' '{print $2}' | \ 685 | awk -F 'value="' '{print $2}' | \ 686 | awk -F '"' '{print $1}') 687 | echo "Auth Token: $auth_token" 688 | } 689 | output=$($CURL -X POST ${gitlab_setting_url} \ 690 | -H 'Accept: */*' \ 691 | -H 'Content-Type: multipart/form-data' \ 692 | --form "_method=patch" \ 693 | --form "authenticity_token=${auth_token}" \ 694 | --form "application_setting[signup_enabled]=0" \ 695 | --form "application_setting[send_user_confirmation_mail]=0" \ 696 | --form "application_setting[minimum_password_length]=8" \ 697 | --form "application_setting[domain_whitelist_raw]=" \ 698 | --form "application_setting[domain_blacklist_enabled]=0" \ 699 | --form "blacklist_type=raw" \ 700 | --form "application_setting[domain_blacklist_raw]=" \ 701 | --form "application_setting[email_restrictions_enabled]=0" \ 702 | --form "application_setting[email_restrictions]=" \ 703 | --form "application_setting[after_sign_up_text]=" \ 704 | 2>&1) 705 | echo "$output" | grep HTTP | grep -E '200|302' || log_fail "$output" 706 | rm -rf ${COOKIES} 707 | echo "Modity config file to enable LDAP" 708 | _ldap_base="ou=users,dc=$(echo $LDAP_DOMAIN | sed 's/\./,dc=/g')" 709 | cat <> odo-gitlab/config/gitlab.rb 710 | #### ODO LDAP Configuration 711 | gitlab_rails['ldap_enabled'] = true 712 | gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' 713 | main: 714 | label: 'LDAP' 715 | host: 'odo-ldap-openldap' 716 | port: 389 717 | uid: 'cn' 718 | bind_dn: '$LDAP_ADMIN' 719 | password: '${LDAP_PASSWD}' 720 | encryption: 'plain' 721 | verify_certificates: true 722 | smartcard_auth: false 723 | active_directory: false 724 | allow_username_or_email_login: true 725 | lowercase_usernames: false 726 | base: '$_ldap_base' 727 | user_filter: '' 728 | attributes: 729 | username: ['cn'] 730 | email: ['mail'] 731 | name: 'displayName' 732 | EOS 733 | EOF 734 | echo "Restart GitLab" 735 | docker restart odo-gitlab 736 | return 0 737 | } 738 | 739 | function init_odo_harbor() { 740 | if [[ "${ODO_INIT_HARBOR}" == "yes" ]]; then 741 | harbor_url=$(grep ODO_HARBOR_URL docker-compose.yaml | awk '{print $NF}') 742 | harbor_host=$(echo ${harbor_url} | awk -F '://' '{print $2}' | awk -F ':' '{print $1}') 743 | harbor_port=$(echo ${harbor_url} | awk -F '://' '{print $2}' | awk -F ':' '{print $2}') 744 | [[ -z "$harbor_port" ]] && harbor_port=80 745 | echo "Waiting for Harbor installer ready ..." 746 | while true 747 | do 748 | sleep 1 749 | [[ -f odo-harbor/harbor.yml.tmpl ]] && break 750 | done 751 | cd odo-harbor || log_fail "Cannot change dir to odo-harbor" 752 | echo "Update harbor.yml" 753 | cp harbor.yml.tmpl harbor.yml 754 | sed -i "s#^hostname: .*#hostname: ${harbor_host}#" harbor.yml 755 | sed -i "s#port: 80#port: ${harbor_port}#" harbor.yml 756 | sed -i 's/^https:/# https:/' harbor.yml 757 | sed -i 's/port: 443/# port: 443/' harbor.yml 758 | sed -i 's/certificate:/# certificate:/' harbor.yml 759 | sed -i 's/private_key:/# private_key:/' harbor.yml 760 | sed -i "s#^harbor_admin_password: .*#harbor_admin_password: ${LDAP_PASSWD}#" harbor.yml 761 | sed -i "s#^data_volume: .*#data_volume: ${ODO_HOME}/odo-harbor/data#" harbor.yml 762 | sed -i "s#location: .*#location: ${ODO_HOME}/odo-harbor/log#" harbor.yml 763 | echo "Start to install Harbor ..." 764 | ./install.sh --with-chartmuseum 765 | else 766 | cd odo-harbor || log_fail "Cannot change dir to odo-harbor" 767 | docker-compose up -d 768 | fi 769 | cd $ODO_HOME 770 | return 0 771 | } 772 | 773 | function init_odo_rancher() { 774 | [[ "${ODO_INIT_RANCHER}" == "yes" ]] || return 0 775 | return 0 776 | } 777 | 778 | function init_odo_jms() { 779 | [[ "${ODO_INIT_JMS}" == "yes" ]] || return 0 780 | return 0 781 | } 782 | 783 | ## Main 784 | check_env 785 | check_odo_cli 786 | check_odo_svc 787 | check_odo_exist 788 | if [[ "${COMPOSE_CMD}" == "start" ]]; then 789 | # Set host before UP containers 790 | if [[ "${COMPOSE_SVC}" == "" ]]; then 791 | set_host_for_sonar 792 | else 793 | echo "${COMPOSE_SVC}" | grep -q "sonar" && set_host_for_sonar 794 | fi 795 | # Pull images 796 | ${DOCKER_COMPOSE} pull ${COMPOSE_SVC} 797 | # UP service container 798 | ${DOCKER_COMPOSE} up -d ${COMPOSE_SVC} 799 | # if start all odo-svc, need init them 800 | if [[ "${COMPOSE_SVC}" == "" ]]; then 801 | init_odo_ldap 802 | init_odo_pg 803 | init_odo_jenkins 804 | init_odo_sonar 805 | init_odo_jira 806 | init_odo_conf 807 | init_odo_gitlab 808 | init_odo_rancher 809 | init_odo_harbor 810 | init_odo_jms 811 | # if start the odo-svc, check and init it 812 | else 813 | echo "${COMPOSE_SVC}" | grep -q "ldap" && init_odo_ldap 814 | echo "${COMPOSE_SVC}" | grep -q "pg" && init_odo_pg 815 | echo "${COMPOSE_SVC}" | grep -q "jenkins" && init_odo_jenkins 816 | echo "${COMPOSE_SVC}" | grep -q "sonar" && init_odo_sonar 817 | echo "${COMPOSE_SVC}" | grep -q "jira" && init_odo_jira 818 | echo "${COMPOSE_SVC}" | grep -q "conf" && init_odo_conf 819 | echo "${COMPOSE_SVC}" | grep -q "gitlab" && init_odo_gitlab 820 | echo "${COMPOSE_SVC}" | grep -q "rancher" && init_odo_rancher 821 | echo "${COMPOSE_SVC}" | grep -q "harbor" && init_odo_harbor 822 | echo "${COMPOSE_SVC}" | grep -q "jms" && init_odo_jms 823 | fi 824 | sleep 2 825 | ${DOCKER_COMPOSE} ps 826 | # Emm...... 827 | elif [[ "${COMPOSE_CMD}" == "start_no_init" ]]; then 828 | if [[ "${COMPOSE_SVC}" == "" ]]; then 829 | set_host_for_sonar 830 | else 831 | echo "${COMPOSE_SVC}" | grep -q "sonar" && set_host_for_sonar 832 | fi 833 | ${DOCKER_COMPOSE} pull ${COMPOSE_SVC} 834 | ${DOCKER_COMPOSE} up -d ${COMPOSE_SVC} 835 | if [[ "${COMPOSE_SVC}" == "" ]]; then 836 | [[ "${ODO_INIT_PG}" == "yes" ]] && chmod_dir odo-pg 837 | [[ "${ODO_INIT_JENKINS}" == "yes" ]] && chmod_dir odo-jenkins 838 | [[ "${ODO_INIT_SONAR}" == "yes" ]] && chmod_dir odo-sonar 839 | else 840 | echo "${COMPOSE_SVC}" | grep -q "pg" && [[ "${ODO_INIT_PG}" == "yes" ]] && chmod_dir odo-pg 841 | echo "${COMPOSE_SVC}" | grep -q "jenkins" && [[ "${ODO_INIT_JENKINS}" == "yes" ]] && chmod_dir odo-jenkins 842 | echo "${COMPOSE_SVC}" | grep -q "sonar" && [[ "${ODO_INIT_SONAR}" == "yes" ]] && chmod_dir odo-sonar 843 | fi 844 | sleep 2 845 | ${DOCKER_COMPOSE} ps 846 | # Stop the container 847 | elif [[ "${COMPOSE_CMD}" == "stop" ]]; then 848 | ${DOCKER_COMPOSE} stop ${COMPOSE_SVC} 849 | sleep 2 850 | ${DOCKER_COMPOSE} ps 851 | # Restart the container 852 | elif [[ "${COMPOSE_CMD}" == "restart" ]]; then 853 | ${DOCKER_COMPOSE} restart ${COMPOSE_SVC} 854 | sleep 2 855 | ${DOCKER_COMPOSE} ps 856 | # List all containers 857 | elif [[ "${COMPOSE_CMD}" == "list" ]]; then 858 | ${DOCKER_COMPOSE} ps 859 | # Down all containers 860 | elif [[ "${COMPOSE_CMD}" == "down" ]]; then 861 | ${DOCKER_COMPOSE} down -v 862 | sleep 2 863 | ${DOCKER_COMPOSE} ps 864 | # Generate license or get initial password 865 | elif [[ "${COMPOSE_CMD}" == "license" ]]; then 866 | if [[ "${COMPOSE_SVC}" == "jira" ]]; then 867 | docker ps | grep -q odo-jira || log_error "Seems there is no Jira Software in this server" 868 | docker exec -it odo-jira getJiraLicense 869 | elif [[ "${COMPOSE_SVC}" == "jira_plugin" ]]; then 870 | docker ps | grep -q odo-jira || log_error "Seems there is no Jira Software in this server" 871 | docker exec -it odo-jira getPluginLicense ${PRODUCT_ID} 872 | elif [[ "${COMPOSE_SVC}" == "conf" ]]; then 873 | docker ps | grep -q odo-conf || log_error "Seems there is no Confluence in this server" 874 | docker exec -it odo-conf getConfLicense ${PRODUCT_ID} 875 | elif [[ "${COMPOSE_SVC}" == "conf_plugin" ]]; then 876 | docker ps | grep -q odo-conf || log_error "Seems there is no Confluence in this server" 877 | docker exec -it odo-conf getPluginLicense ${PRODUCT_ID} 878 | elif [[ "${COMPOSE_SVC}" == "jenkins" ]]; then 879 | docker ps | grep -q odo-jenkins || log_error "Seems there is no Jenkins in this server" 880 | docker exec -it odo-jenkins sh -c 'cat /var/jenkins_home/secrets/initialAdminPassword' 881 | fi 882 | # Cleanup all 883 | elif [[ "${COMPOSE_CMD}" == "cleanup" ]]; then 884 | echo -en "\033[31;1m [ DANGER ] \033[0m" 885 | echo -e "\033[33;1mThis action will wipe all ODO data\033[0m" 886 | echo -en "\033[33;1mDo you really wanna to this? \033[0m" 887 | read -p "[y/N] " _CLEANUP 888 | [[ "${_CLEANUP,,}" == 'y' ]] || log_error "Abort cleanup" 889 | ${DOCKER_COMPOSE} down 890 | sleep 2 891 | ${DOCKER_COMPOSE} ps 892 | # Remove generated dirs 893 | [[ -f .gitignore ]] && { 894 | for clean_dir in $(grep 'odo-' .gitignore | grep -v '#'); do 895 | rm -rf ${clean_dir} 896 | done 897 | } 898 | # Check and disable sonar LDAP config 899 | sed -i 's/^sonar.security.realm=LDAP/#sonar.security.realm=LDAP/' odo-sonar/sonar.properties 900 | # Remove cookie file 901 | rm -rf ${COOKIES} 902 | fi 903 | --------------------------------------------------------------------------------