【DevOps實(shí)踐】4. Ubuntu下安裝配置代碼檢測(cè)工具SonarQube+MySQL

1. 摘要

SonarQube是一款用于代碼質(zhì)量管理的開源工具蚤告,它主要用于管理源代碼的質(zhì)量忍法。 通過插件形式,可以支持眾多計(jì)算機(jī)語言少孝,比如 java, C#, go,C/C++, PL/SQL, Cobol, JavaScrip, Groovy 等熬苍。sonar可以通過PMD,CheckStyle,Findbugs等等代碼規(guī)則檢測(cè)工具來檢測(cè)你的代碼稍走,幫助你發(fā)現(xiàn)代碼的漏洞,Bug柴底,異味等信息婿脸。
本文講解該軟件在Ubuntu環(huán)境的搭建過程。

2. 內(nèi)容

2.1 前置環(huán)境

從Sonar7.8版本開始柄驻,要求支持Java11狐树,不再支持MySQL數(shù)據(jù)庫。
本文講解目前主流環(huán)境下(在Java8(JDKv1.8.0)和MySQL)版本中安裝Sonar7.7的完整過程鸿脓。

2.2 配置MySQL數(shù)據(jù)庫

登錄MySQL

mysql -u root -p

create database sonar character set utf8 collate utf8_general_ci;
create user 'sonar' identified by 'sonar';
grant all on sonar.* to 'sonar'@'%' identified by 'sonar';
grant all on sonar.* to 'sonar'@'localhost' identified by 'sonar';
flush privileges;

輝哥實(shí)際采用寶塔完成數(shù)據(jù)庫的創(chuàng)建和配置褪迟,數(shù)據(jù)庫名:sonar 用戶名:sonar 同以上命令實(shí)現(xiàn)。

2.2 下載安裝sonar

2.2.1 下載安裝sonar

(1)在國內(nèi)從官網(wǎng)下載sonar的速度特別慢答憔。下載地址:https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-7.7.zip
下載后上傳到Linux服務(wù)器,進(jìn)行解壓縮安裝掀抹。

$ unzip sonarqube-7.7.zip
$ mkdir /opt/sonar
$ mv sonarqube-7.7/* /opt/sonar/

(2)sonar無法使用root啟動(dòng)虐拓,需要?jiǎng)?chuàng)建新的sonar用戶,密碼自行記錄。

$ useradd sonar
$ passwd sonar

賦予普通用戶sonar具有sonar軟件的所有讀寫執(zhí)行權(quán)限傲武。
chown將指定文件的擁有者改為指定的用戶或組蓉驹,用戶可以是用戶名或者用戶ID;組可以是組名或者組ID揪利;文件是以空格分開的要改變權(quán)限的文件列表态兴,支持通配符。-R表示 處理指定目錄以及其子目錄下的所有文件

$ chown -R sonar. /opt/sonar/

(3)sonar默認(rèn)偵聽接口為9000疟位。啟動(dòng)前采用netstat查看9000接口有無被占用瞻润。修改sonar配置文件。
9001默認(rèn)被自帶的elastic search啟動(dòng)占用甜刻,也要保證該端口不被其他進(jìn)程占用绍撞。

$ netstat -nltp
$ cd /opt/sonar/
$ vim conf/sonar.properties

編輯的核心內(nèi)容如下:

sonar.jdbc.username=sonar 
sonar.jdbc.password=***#需要修改訪問數(shù)據(jù)庫的密碼

sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false

sonar.web.port=9000 #偵聽端口

sonar.web.host=0.0.0.0 # 開放,允許所有IP訪問該端口得院。
#sonarWEB登錄用戶密碼
sonar.login=admin
sonar.password=***#需要修改為訪問頁面的初始密碼傻铣,可以修改

(4)啟動(dòng)sonarqube
啟動(dòng)sonarqube:

$ su sonar
$ ./bin/linux-x86-64/sonar.sh start

查看sonarqube,這個(gè)表示啟動(dòng)成功祥绞。16395是其進(jìn)程號(hào)非洲。

$ ./bin/linux-x86-64/sonar.sh status
SonarQube is running (16395)

kill -9 進(jìn)程號(hào)可殺死鸭限。也可以采用stop命令關(guān)閉。

$ ./bin/linux-x86-64/sonar.sh stop

2.2.2 常見啟動(dòng)失敗問題及排查

如果啟動(dòng)不成功两踏,可能有各種原因败京。可以查看啟動(dòng)日志,并逐個(gè)排查問題解決缆瓣。

$ tail -f logs/sonar.log

(1)JAVA版本不合適

vim logs/sonar.log
【問題】

WrapperSimpleApp: Encountered an error running main: java.lang.IllegalStateException: SonarQube requires Java 11 to run
java.lang.IllegalStateException: SonarQube requires Java 11 to run
        at com.google.common.base.Preconditions.checkState(Preconditions.java:173)

【分析結(jié)論】
需要Java11運(yùn)行喧枷。這個(gè)是安裝sonarqube-7.9 TLS版本遇到的問題。改為安裝sonarqube-7.7版本弓坞,以便支持JDK1.8的環(huán)境隧甚。

(2)以root用戶運(yùn)行

【問題】
vim logs/sonar.log

2021.03.18 15:19:02 INFO  app[][o.s.a.AppFileSystem] Cleaning or creating temp directory /opt/sonar/temp
2021.03.18 15:19:02 INFO  app[][o.s.a.es.EsSettings] Elasticsearch listening on /127.0.0.1:9001
2021.03.18 15:19:02 INFO  app[][o.s.a.p.ProcessLauncherImpl] Launch process[[key='es', ipcIndex=1, logFilenamePrefix=es]] from [/opt/sonar/elasticsearch]: /opt/sonar/elasticsearch/bin/elasticsearch
2021.03.18 15:19:02 INFO  app[][o.s.a.SchedulerImpl] Waiting for Elasticsearch to be up and running
2021.03.18 15:19:03 INFO  app[][o.e.p.PluginsService] no modules loaded
2021.03.18 15:19:03 INFO  app[][o.e.p.PluginsService] loaded plugin [org.elasticsearch.transport.Netty4Plugin]
2021.03.18 15:19:05 WARN  app[][o.s.a.p.AbstractProcessMonitor] Process exited with exit value [es]: 1
2021.03.18 15:19:05 INFO  app[][o.s.a.SchedulerImpl] Process [es] is stopped
2021.03.18 15:19:05 INFO  app[][o.s.a.SchedulerImpl] SonarQube is stopped
<-- Wrapper Stopped

vim es.log

java.lang.RuntimeException: can not run elasticsearch as root
        at org.elasticsearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:103) ~[elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:170) ~[elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:333) [elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:159) [elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:150) [elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:86) [elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:124) [elasticsearch-cli-6.6.2.jar:6.6.2]
        at org.elasticsearch.cli.Command.main(Command.java:90) [elasticsearch-cli-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:116) [elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:93) [elasticsearch-6.6.2.jar:6.6.2]
2021.03.18 15:19:05 WARN  es[][o.e.b.ElasticsearchUncaughtExceptionHandler] uncaught exception in thread [main]
org.elasticsearch.bootstrap.StartupException: java.lang.RuntimeException: can not run elasticsearch as root
        at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:163) ~[elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:150) ~[elasticsearch-6.6.2.jar:6.6.2]
        at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:86) ~[elasticsearc

【分析結(jié)論】
sonar.log沒有有效信息。但是es.log明確指出不能使用root用戶啟動(dòng)的渡冻。
切換到sonar用戶戚扳,重新啟動(dòng)sonar服務(wù)了。

(3)端口被占用

vim logs/sonar.log
【問題】

sh-4.4$ ./bin/linux-x86-64/sonar.sh console
Running SonarQube...
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
jvm 1    |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
jvm 1    | 
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.s.a.AppFileSystem] Cleaning or creating temp directory /opt/sonar/temp
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.s.a.es.EsSettings] Elasticsearch listening on /127.0.0.1:9001
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.s.a.p.ProcessLauncherImpl] Launch process[[key='es', ipcIndex=1, logFilenamePrefix=es]] from [/opt/sonar/elasticsearch]: /opt/sonar/elasticsearch/bin/elasticsearch
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.s.a.SchedulerImpl] Waiting for Elasticsearch to be up and running
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.e.p.PluginsService] no modules loaded
jvm 1    | 2021.03.15 21:42:37 INFO  app[][o.e.p.PluginsService] loaded plugin [org.elasticsearch.transport.Netty4Plugin]
jvm 1    | 2021.03.15 21:42:50 INFO  app[][o.s.a.SchedulerImpl] Process[es] is up
jvm 1    | 2021.03.15 21:42:50 INFO  app[][o.s.a.p.ProcessLauncherImpl] Launch process[[key='web', ipcIndex=2, logFilenamePrefix=web]] from [/opt/sonar]: /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/opt/sonar/temp -Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -cp ./lib/common/*:/opt/sonar/lib/jdbc/mysql/mysql-connector-java-5.1.46.jar org.sonar.server.app.WebServer /opt/sonar/temp/sq-process6941314718593124808properties
jvm 1    | 2021.03.15 21:42:51 INFO  app[][o.s.a.SchedulerImpl] Process [web] is stopped
jvm 1    | 2021.03.15 21:42:52 INFO  app[][o.s.a.SchedulerImpl] Process [es] is stopped
jvm 1    | 2021.03.15 21:42:52 INFO  app[][o.s.a.SchedulerImpl] SonarQube is stopped
jvm 1    | 2021.03.15 21:42:52 WARN  app[][o.s.a.p.AbstractProcessMonitor] Process exited with exit value [es]: 143
wrapper  | <-- Wrapper Stopped

然后vim logs/web.log族吻,保存信息如下:

2021.03.15 21:42:51 WARN  web[][o.s.p.ProcessEntryPoint] Fail to start web
java.lang.RuntimeException: org.apache.catalina.LifecycleException: Failed to initialize component [StandardServer[-1]]
        at com.google.common.base.Throwables.propagate(Throwables.java:160)
        at org.sonar.server.app.EmbeddedTomcat.start(EmbeddedTomcat.java:65)
        at org.sonar.server.app.WebServer.start(WebServer.java:51)
        at org.sonar.process.ProcessEntryPoint.launch(ProcessEntryPoint.java:113)
        at org.sonar.process.ProcessEntryPoint.launch(ProcessEntryPoint.java:100)
        at org.sonar.server.app.WebServer.main(WebServer.java:91)
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [StandardServer[-1]]
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:112)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
        at org.apache.catalina.startup.Tomcat.start(Tomcat.java:427)
        at org.sonar.server.app.EmbeddedTomcat.start(EmbeddedTomcat.java:61)
        ... 4 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [StandardService[Tomcat]]
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:112)
        at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:875)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
        ... 7 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to initialize connector [Connector[HTTP/1.1-9001]]
        at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)
        at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
        ... 9 common frames omitted

【分析結(jié)果】
sonar.log的日志表示sonar的web服務(wù)啟動(dòng)后又被關(guān)閉了帽借。無法確定其原因。
web.log的日志表示之前配置的已經(jīng)被占用超歌,導(dǎo)致連接失敗砍艾。" Failed to initialize connector [Connector[HTTP/1.1-9001]]"
9001端口默認(rèn)被es占用,改為9000即可巍举。

輸入curl http://127.0.0.1:9000可以獲取反饋頁面內(nèi)容脆荷。

(4)

【問題描述】
sonar先啟動(dòng)成功,然后not running了懊悯。
vim ./logs/sonar.log

WrapperSimpleApp: Encountered an error running main: java.nio.file.AccessDeniedException: /opt/sonar/temp/conf/es/log4j2.properties
java.nio.file.AccessDeniedException: /opt/sonar/temp/conf/es/log4j2.properties
        at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
        at sun.nio.fs.UnixFileSystemProvider.implDelete(UnixFileSystemProvider.java:244)
        at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
        at java.nio.file.Files.delete(Files.java:1126)
        at org.sonar.process.FileUtils2$DeleteRecursivelyFileVisitor.visitFile(FileUtils2.java:186)
        at org.sonar.process.FileUtils2$DeleteRecursivelyFileVisitor.visitFile(FileUtils2.java:181)
        at java.nio.file.Files.walkFileTree(Files.java:2670)
        at java.nio.file.Files.walkFileTree(Files.java:2742)
        at org.sonar.process.FileUtils2.deleteDirectoryImpl(FileUtils2.java:143)
        at org.sonar.process.FileUtils2.deleteDirectory(FileUtils2.java:112)
        at org.sonar.application.AppFileSystem$CleanTempDirFileVisitor.visitFile(AppFileSystem.java:117)
        at org.sonar.application.AppFileSystem$CleanTempDirFileVisitor.visitFile(AppFileSystem.java:101)
        at java.nio.file.Files.walkFileTree(Files.java:2670)
        at org.sonar.application.AppFileSystem.createOrCleanTempDirectory(AppFileSystem.java:96)
        at org.sonar.application.AppFileSystem.reset(AppFileSystem.java:62)
        at org.sonar.application.App.start(App.java:55)
        at org.sonar.application.App.main(App.java:78)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.tanukisoftware.wrapper.WrapperSimpleApp.run(WrapperSimpleApp.java:240)
        at java.lang.Thread.run(Thread.java:748)
<-- Wrapper Stopped

【分析結(jié)論】
之前因?yàn)閞oot賬戶運(yùn)行導(dǎo)致es失敗蜓谋。切換到sonar賬戶后,還是失敗炭分,報(bào)錯(cuò)如上桃焕。沒有/opt/sonar/temp/conf/es權(quán)限?
刪除sonarqube temp目錄重新運(yùn)行就成功了捧毛。

sudo rm -rf temp

2.2.3 配置https域名和反向代理

增加NGINX配置的反代理观堂,以便安全保護(hù)。這個(gè)步驟不是必選項(xiàng)呀忧。

在nginx配置增加sonar的路由型将,然后把conf/sonar.properties的開放IP“sonar.web.host=0.0.0.0 ”注釋掉關(guān)閉。
最終域名:
https://sonar.artarva.com/

配置參考文章《【DevOps實(shí)踐】2. 使用NGINX配置Jenkins的https域名訪問》

2.3 登錄

https://sonar.artarva.com/就可以訪問sonarqube主頁了荐虐。

3. 參考

(1)Ubuntu 16.04下安裝配置SonarQube+MySQL
https://www.linuxidc.com/Linux/2017-05/143860.htm
【說明】主要參考這個(gè)七兜。

(2)sonarqube環(huán)境搭建采坑詳解
https://blog.csdn.net/weixin_40686603/article/details/90208627

(3)SonarQube 7.9.x LT安裝
https://blog.csdn.net/u010948569/article/details/111991998
【說明】安裝參考這個(gè),需要JAVA11福扬,無奈放棄腕铸。
[1] SonarQube安裝教程與簡(jiǎn)單使用(基于Centos7惜犀,JDK1.8)

[2] 下載文件列表【最后顯示所有版本】
https://www.sonarqube.org/downloads/
https://docs.sonarqube.org/7.7/requirements/requirements/
【說明】7.7為最后一個(gè)支持JDK1.8的版本
[3] 有安裝sonar scanner的幫助

(4)GO語言監(jiān)測(cè)配置
How to run SonarQube for Go code using Jenkins
https://stackoverflow.com/questions/63832311/how-to-run-sonarqube-for-go-code-using-jenkins

https://docs.sonarqube.org/latest/analysis/languages/go/

(5)Jenkins+SonarQube+Gitlab搭建自動(dòng)化持續(xù)代碼掃描質(zhì)量平臺(tái)
https://blog.csdn.net/zuozewei/article/details/84539396
【說明】介紹sonar的作用整體。

(6) SonarQube集成golang檢測(cè)
https://blog.csdn.net/baidu_36943075/article/details/90634160

(7)GO項(xiàng)目配置
https://docs.sonarqube.org/latest/analysis/languages/go/

(8) sonarqube SonarGo 搭建和golang代碼檢視的使用教程
http://www.reibang.com/p/95ae320aa46d

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狠裹,一起剝皮案震驚了整個(gè)濱河市虽界,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涛菠,老刑警劉巖莉御,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異俗冻,居然都是意外死亡礁叔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門迄薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琅关,“玉大人,你說我怎么就攤上這事讥蔽』烈祝” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵冶伞,是天一觀的道長(zhǎng)新症。 經(jīng)常有香客問我,道長(zhǎng)响禽,這世上最難降的妖魔是什么徒爹? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮金抡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腌且。我一直安慰自己梗肝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布铺董。 她就那樣靜靜地躺著巫击,像睡著了一般。 火紅的嫁衣襯著肌膚如雪精续。 梳的紋絲不亂的頭發(fā)上坝锰,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音重付,去河邊找鬼顷级。 笑死,一個(gè)胖子當(dāng)著我的面吹牛确垫,可吹牛的內(nèi)容都是我干的弓颈。 我是一名探鬼主播帽芽,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翔冀!你這毒婦竟也來了导街?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤纤子,失蹤者是張志新(化名)和其女友劉穎搬瑰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體控硼,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泽论,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了象颖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佩厚。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖说订,靈堂內(nèi)的尸體忽然破棺而出抄瓦,到底是詐尸還是另有隱情,我是刑警寧澤陶冷,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布钙姊,位于F島的核電站,受9級(jí)特大地震影響埂伦,放射性物質(zhì)發(fā)生泄漏煞额。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一沾谜、第九天 我趴在偏房一處隱蔽的房頂上張望膊毁。 院中可真熱鬧,春花似錦基跑、人聲如沸婚温。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栅螟。三九已至,卻和暖如春篱竭,著一層夾襖步出監(jiān)牢的瞬間力图,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工掺逼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吃媒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像晓折,于是被迫代替她去往敵國和親惑朦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容